Define #DeclareRoles annotation programmatically - rest

The JAVA EE #DeclareRoles annotation is a way to declare the list of possible roles of the users to match with the annotation #RolesAllowed.
But what if our roles are stored in database and if the list of the potential roles is long ?
I currently use roles to specify an atomic access to functionnalities on my website, so I have a long list of roles as some users can access functionnality-1 but not the 2, and some can on the 2 but not on the 1, etc...
I want to avoid editing the #DeclareRoles annotation every time I am creating a new role for a new functionnality, so the question is :
Is there any way to programmatically setup the #DeclareRoles annotation or to specify that it should load from a database ?

Since the introduction of the JavaEE 8 security API you have the ability to write your own identity store. This allows you to fetch users and user data from a custom location and a custom service. You asked about using a database - so here is an example using a database facade together with a custom identity store;
#ApplicationScoped
public class MyIdentityStore implements IdentityStore {
#EJB private UserFacade userFacade;
#Override
public int priority() {
return 50;
}
#Override
public Set<ValidationType> validationTypes() {
return EnumSet.of(ValidationType.PROVIDE_GROUPS, ValidationType.VALIDATE);
}
#Override
public Set<String> getCallerGroups(CredentialValidationResult validationResult) {
final String userName = validationResult.getCallerPrincipal().getName();
final User user= usersFacade.find(userName);
return user.getRoles();
}
public CredentialValidationResult validate(UsernamePasswordCredential credential) {
/* Handle validation/login of the user here */
}
}
To explain the above slightly more - the getCallerGroups() will return the roles that the user is part of - something you can then use throughout the JavaEE security API and lockdown methods such as #RolesAllowed. The validate() method handles the validation of the user when a check is requested by the container. Finally, the validationTypes() method simply specifies what this Identity store should be used for - in this case we have specified both the fetching of roles and handling of validation.
So since EE8 introduced this - it has become really flexible and easy to take advantage of the security features in the platform.
Here are some really great references on the subject;
https://www.ibm.com/developerworks/library/j-javaee8-security-api-1
https://www.ibm.com/developerworks/library/j-javaee8-security-api-2
https://www.ibm.com/developerworks/library/j-javaee8-security-api-3
https://www.baeldung.com/java-ee-8-security

Related

ASP.NET Core 6 web app with Identity - Ind. Accounts. How can I add a role and add 2 users to that role?

Ok, I remember back in regular ASP.NET 4 (before .NET Core - 2015 ish) it was not this convoluted to add a user to a role. But now I found it to be very difficult.
Using Sqlite database, and all the scaffolding and account creation works great. Even imported my contact subscriber list and it seamlessly created the CRUD - awesome.
Now I only need to restrict this page to Admins only, which I did this and works -- no access. I am on the step to add an Admin role and add a user to it.
After reading and trying code from many sites I find myself here for some direction.
Also I see a role and role claim which is confusing..
Ref: How to create roles in ASP.NET Core and assign them to users?
This may work if I knew where to put this for it to find the proper references.
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _rolesManager;
Not sure where the ApplicationUser and ApplicationRole is coming from.
Assuming you have correctly configured Identity in your application with something similar to the following
builder.Services
.AddIdentity<IdentityUser, IdentityRole>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<WebApplication2Context>();
(in your case, IdentityUser is probably going to map to your AspNetUser class and IdentityRole would be your AspNetRole class, though I'm not sure where you got those classes or whether they properly inherit IdentityUser<T> and IdentityRole<T> - if they don't, you've gone down a dark and scary road...)
Once that's done (and you've applied all the EF Core migrations, etc. to get your database correctly built), you can do something like this to add a role and add a user to it
#page
#model IndexModel
#using Microsoft.AspNetCore.Identity
#inject UserManager<IdentityUser> _userManager
#inject RoleManager<IdentityRole> _roleManager
#{
ViewData["Title"] = "Home page";
await _roleManager.CreateAsync(new IdentityRole("Admin"));
await _userManager.CreateAsync(new IdentityUser("foobar") { Email = "foo#bar.com" });
var newUser = await _userManager.FindByNameAsync("foobar");
await _userManager.AddToRoleAsync(newUser, "Admin");
}
If you're not sure your existing AspNetXxx classes are correct or correctly map to the related Identity classes, I'd suggest you start over and use the default implementations as much as possible. You can read about Identity Model Customization in ASP.NET Core to learn about the model and how all the different tables work together.
I think you need to "link" your "MyPolicyName" to your MVC.
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0#apply-policies-to-razor-pages
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace AuthorizationPoliciesSample.Pages;
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Model : PageModel { }
...
Because of this "string-matching-magic" I would create a single-source-of-truth class.
public static class MyPolicyNames
{
public static string AtLeast21PolcyName = "AtLeast21PolicyName";
}
and refer to this const in both places. And eliminate future "where are the magic-strings" scavenger hunts.
=============
So you are using a Policy, but your "policy rule" is to then check a Role.
Should you be just using Role?
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0
I guess M$ says its "ok"
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0#policy-based-role-checks

How to include a user manager to another application for ASP.NET Core 3.1

I'm developing two different applications, I will name them A and B.
A is an internet platform, where you can logon only if you have a valid user account.
B is an intranet platform, where users can authenticate via Active Directory. An administrator using application B should be able to create new user accounts for application A.
After the creation of a new user account, I want to be able to realize different functions, for example to send an e-mail to the registered mail address, so the new user can change the default password.
All the functionalities that I want to implement, can be done by the UserManager (see section "Use another app to add users" in the following link: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-3.1&tabs=visual-studio#disable-register-page).
Based on this I implemented the following code:
public class ControllerClass : Controller
{
private readonly HelperClass _helper;
private readonly UserManager<IdentityUser> _userManager;
public ControllerClass (UserManager<IdentityUser> userManager)
{
_userManager = userManager;
_helper= new HelperClass (userManager);
}
}
public class HelperClass
{
private readonly DbContext _db;
private readonly UserManager<IdentityUser> _userManager;
public HelperClass (UserManager<IdentityUser> userManager)
{
_db = new DbContext ();
_userManager = userManager;
}
private async Task<string> EnsureUser(string userName, string userPassword)
{
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
{
user = new IdentityUser()
{
UserName = userName
};
await _userManager.CreateAsync(user, userPassword);
}
return user.Id;
}
internal async void CreateUser(UserVM uvm, int id)
{
var userId = await EnsureUser(uvm.userName, uvm.userPassword);
// TODO ...
}
}
Unfortunately I didn't manage to include the UserManager into my application B. I got the following error message: "An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[IdentityUser]' while attempting to activate 'ControllerClass '."
Do you have an idea, how I can add the UserManager to manage the users for another application?
Well, the specific error you're getting is simply because UserManager<TUser> is not registered in the service collection. In order to inject anything, you must first register it. In your actual user-facing app, that's being done by services.AddIdentity(). However, that does a lot more than just register UserManager<TUser>, so you shouldn't just run off and add the same command to your second app.
You could add a registration for it specifically:
services.AddScoped<UserManager<ApplicationUser>>();
However, it actually has a ton of dependencies, each of which would also need to be registered. If you look at the constructor, there's seven services not registered out of the box, many of which have their own dependency trees. Long and short, it's a pain. There's also the matter of separation of concerns, here. This would require adding in the whole data layer from the other app.
Your best bet is to simply expose an API on the Identity app (and lock it down, of course). That way, all the logic of working with users stays with the rest of that logic. The administration app, then, can call out to the API to add, update, delete, etc. users without having to have knowledge of how that's actually done.
Answering after 2 years. For future reader, You can use
services.AddIdentityCore<IdentityUser>();
which adds necessary services that are for user-management add/delete etc. without adding Login service.
to add EntityFramework you can create context and use like this
services.AddDbContext<ApplicationAuthDbContext>(options =>
{
// Configure the context to use postgresql.
options.UseNpgsql(config.GetConnectionString("AuthDbContext"))
.UseSnakeCaseNamingConvention();
});
services.AddIdentityCore<IdentityUser>()
.AddEntityFrameworkStores<ApplicationAuthDbContext>();
For more information
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.identityservicecollectionextensions.addidentitycore?view=aspnetcore-6.0

Rundeck - User Group Source Plugins - Java Plugin Type

I want to understand the use case/usage of "User Group Source Plugins - Java Plugin Type"
1) can I use the plugin's returned roles/groups in authorization policies(/etc/rundeck/myadmin.aclpolicy)
2) what is the property and its value of this plugin, I should mention here?
framework.plugin.UserGroupSource.[your_plugin_name].[property]=value
In below case, framework.plugin.UserGroupSource.example-user-group-source-plugin.[property]=value
3) Can I connect to a RDBMS and get the roles from DB using java class constuctor
package example;
#Plugin(name = "example-user-group-source-plugin",service= ServiceNameConstants.UserGroupSource)
public class ExampleUserGroupSourcePlugin implements UserGroupSourcePlugin {
List<String> groups = new ArrayList<>();
public ExampleUserGroupSourcePlugin() {
groups.add("RUNDECK_USER"); //This group would get added to all users
//TODO: DBConnect code to get roles from RDBMS
}
#Override
public List<String> getGroups(final String username, final Map<String, Object> config) {
//some code
return groups;
}
}```
Yes, the ACL definition can take the roles defined in your plugin. In the same way which LDAP roles for example.
What you define in your code as you see here (maybe the documentation needs some update to specify that).
Theoretically yes, using the right way to connect to DB like this.

enverse-how to customize user id in customized revision listner

i am using jpa with hibernate envers of micro service.
i tried
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setUserName( userContext.getUserName() );
}
}
it saves username better.but i want to save user name as"by system" when updates the record by another micro service and when user updates should save the user name as above.how to customize above code as my requirement
It would seem the most logical based on your supplied code might be to simply add a boolean flag to your UserContext thread local variable and simply check that inside the listener.
By default this flag would be false but for your special microservice or business use case, you could alter that state temporarily, run your process, and clear that state after you've finished, very much like a web filter chain works in web applications.

Securing Entities with Claims Based Authorization in Web Api 2 OData Endpoint

Given the following Controller
namespace MyNamespace.Api.Controllers
{
[Authorize]
public class AccountController : ODataController
{
private Entities db = new Entities();
// GET odata/Account
[Queryable]
[ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Read", Resource = "Account")]
public IQueryable<Account> GetAccount()
{
return db.Accounts();
}
...
}
}
I override the ClaimsAuthorizationManager.CheckAccess(...)
public class AuthorizationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
return Policies.Validate(resource, action);
}
}
This is useful only to the point where I can check whether or not the Current Principal in general can Read Account. However, if I'd want to check which accounts a certain user is allowed to Read, I am lost.
Let's say I have a Manager user who should be able to read all Accounts for which he is a manager for whereas a non-manager user should be able to read only their own account.
Is there a best practice for this or have you done something like this previously and give me a few hints to look for?
I do not use ClaimsPrincipalPermissionAttribute because I cannot pass any dynamic parameters to it like requested Account from your sample.
Have a look at the book "Pro APS.NET Web API Security" page 97. They suggest to invoke AuthorizationManager from your controller action implementation by code new IdentityConfiguration().ClaimsAuthorizationManager.CheckAccess(context), where context is constructed manually so you can pass Account requested (for example) as Resource to check it in your AuthorizationManager implementation.
Also have a look at pluralsight training "Introduction to Identity and Access Control in .NET 4.5". There are also some info about how to implement claim-based security in Web API.
Now I am in progress of implementing the security you are talking about and I am interesting in the subject too.
My case is: role Administrator is assigned by Country, every Administrator can see entities only related to the countries they have access to.
UPDATE: After several projects I forgot about Claims-based security as this is extremely difficult way to make security checks. Today I use decorator pattern where all the security checks are done. It appears to be very easy to implement security even in OData Controllers like this:
public IQueriable MyQuriableEntitySet
{
get{ return implementationWithoutSecurity.MyQuriableEntitySet.Where(e=>e.Country.Code = currentUser.AssignedTo.CountryCode || currentUser.IsSuperAdmin); }
}