I have a LDAP connection set up in my Keycloak. I've managed to import the normal LDAP roles into keycloak with a mapper. In our LDAP we have roles also mapped as user attributes, so like cn, sn, c ... we have attributeRoles. Of course these are not really roles from the technical point of view but user attributes(They are used in our application as roles).
What I want to achieve is to map these user attribute roles(attributeRoles) to real roles in keycloak.
Did any of you have this specific problem and managed to solve it somehow?
Any help would be appreciated.
Update the onImportUserFromLDAP in the RoleLDAPStorageMapper with the following code:
Map<String, Set<String>> attributes = ldapUser.getAttributes();
for (Map.Entry<String, Set<String>> entry : attributes.entrySet()){
if(entry.getKey().equals(<ATTRIBUTE>)){
// Try to import the attribute to Keycloak roles
importAttributesFunction(user, realm, entry.getValue());
}
}
and here you have the importAttributesFunction:
public void importAttributesFunction(UserModel user, RealmModel realm, Set<String> sRoles) {
for(String sRole: sRoles){
RoleContainerModel roleContainer = getTargetRoleContainer(realm);
RoleModel role = roleContainer.getRole(sRole);
if (role == null) {
role = roleContainer.addRole(sRole);
}
if(!user.hasRole(role)) {
user.grantRole(role);
}
}
}
Hope it helps.
Related
Im running Skorubas implementation of IdentityServer4
https://github.com/skoruba/IdentityServer4.Admin
For some reason I end up receiving a single role-claim with the claim-type "role" and a value of an array with all roles for the current user:
["SkorubaIdentityAdminAdministrator","MyRole"]
Now if I would to protect a "page" using the Authorize-attribute:
[Authorize(Role="MyRole")]
This would always end up with an access denied, since ASP.net Core expects multiple claims with the same claim-type, so in this case the claims would be
type | value
role:"SkorubaIdentityAdminAdministrator"
role:"MyRole"
is there any "best practice" to either parse the claims received and reformat them before they are processed by ASP.net core, or to tell the OpenIdConnect extension to handle the array-format as multiple claims?
Generally claims received in JWTs can be arrays or objects as well as simple types. The way to deal with this when using .NET attributes for authorization is via policies.
They are pretty simple and this Curity tutorial has some examples. This code snippet shows that the entire ClaimsPrincipal is available to policies so you could work with array claims easily in your use case:
options.AddPolicy("lowRisk", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(claim =>
claim.Type == "risk" && Int32.Parse(claim.Value) < 50
)
)
);
[HttpGet("lowrisk")]
[Authorize( Policy = "lowRisk")]
public IActionResult LowRisk()
{
return Ok();
}
Turns out that you can create your own ClaimActions, in the example above I had to do the following:
Firts of all.. create a new class:
public class RoleClaimAction : ClaimAction
{
private const string RoleClaimType = "role";
public RoleClaimAction() : base(RoleClaimType, ClaimValueTypes.String)
{
}
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
{
//Map array of roles to separate role claims
var roles = userData.TryGetStringArray(RoleClaimType)?.ToList();
if (roles!.Any())
{
foreach (var role in roles!)
{
AddRoleClaim(identity, role, issuer);
}
return;
}
//If we only have one role (not an array), add it as a single role claim
var singleRole = userData.TryGetString(RoleClaimType);
if(!string.IsNullOrEmpty(singleRole))
AddRoleClaim(identity, singleRole, issuer);
}
private void AddRoleClaim(ClaimsIdentity identity, string role, string issuer)
{
identity.AddClaim(new Claim(JwtClaimTypes.Role, role, ClaimValueTypes.String, issuer));
}
}
This will simply validate that the user has a claim called roles, and the re-map the array-values to separate role-claims, which then "hooks" into the auth-framework.
To add your ClaimAction, simply add it as the following to your OpenIdConnectOptions:
options.ClaimActions.Add(new RoleClaimAction())
Now Authorize-attributes with roles, and the User.IsInRole(string) should work properly.
Assume i have the following Role based authorization for an action
[AuthorizeDBRoleAttribute(Roles = "Manager")]
public ActionResult Welcome()
{
return View();
}
here is the AuthorizeDBRoleAttribute class
public class AuthorizeDBRoleAttribute : AuthorizeAttribute
{
public string Roles { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContextBase)
{
//Bind User Roles from Database here
string userRoles = "Manager,Supervisor,Inspector";
if (userRoles.IndexOf(Roles) > -1)
return true;
else
return false;
}
}
I have separate DB tables Roles and Users
Assume the current user logged in is of Role Manager. How does this "AuthorizeDBRoleAttribute" attribute knows the current user's role so it can let access to the Action method
How to setup Role based authorization was discussed in this post. I want to drag it a bit further in to the next step on how MVC figure out the current user's role etc
You start with current IPrincipal, taken from the http context and set there by the authentication module.
Then, depending on your current approach (which we obviously don't know) you either have roles already stored in the principal object or you have only the user name and you retrieve roles from the database for the current user name.
The author of the code you cite even put a comment there - retrieve user roles for the current user name, more or less something like:
string username = httpContextBase.User.Identity.Name;
var roles = whereeverYourRolesAreStored.RolesForUser( username );
Is it possible to extend org.restlet.data.ClientInfo? I need a convenient way of adding a List<String> permissions to complement the existing List<Role> roles. In a perfect world I would be able to add List<Permission> permissions but the former is perfectly acceptable.
I need to be able to get this from the request: org.restlet.resource.Resource.getRequest().getClientInfo().getPermissions()
I don't think that it's possible to add something within the class ClientInfo since it's a class that is managed by the Restlet engine. You can't subclass it to add a field permissions (you don't have the hand on the client info instantiation).
That said, you can leverage the context attributes. I mean that you can fill within your Enroler implementation an attribute permissions for the request, as described below:
public class MyEnroler implements Enroler {
private Application application;
public MyEnroler(Application application) {
this.application = application;
}
public void enrole(ClientInfo clientInfo) {
// Roles
Role role = new Role(application, "roleId",
"Role name");
clientInfo.getRoles().add(role);
// Permissions
Request request = Request.getCurrent();
List<Permission> permissions = new ArrayList<Permission>();
request.getAttributes().put("permissions", permissions);
Permission permission = (...)
permissions.add(permission);
}
Hope it helps you,
Thierry
I was reading up a lot of blog posts and stackoverflow answers but still I am unable to find a real world open source project which uses claims based authentication and authorization, so that I can get an idea on how to actually implement these.
So far what I could find is Thinktecture.IdentityModel and this blog implements a claims based authorization on a sample website. If you guys could point me some Open source projects using claims, that would be really helpful.
What I am interested is how to retrieve claims for my application using the database.
So far, what I have tried is that using an in memory claims store to simulate the databsae, I have created a CustomClaimsTransformer and CustomAuthorisationManager like this.
public class CustomClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
//validate name claim
string nameClaimValue = incomingPrincipal.Identity.Name;
return CreatePrincipal(nameClaimValue);
}
private ClaimsPrincipal CreatePrincipal(string userName)
{
int userId = ClaimStore.Users.First(u => u.Value == userName).Key;
var claims = ClaimStore.ClaimsSet.Where(c => c.Key == userId);
var claimsCollection = claims.Select(kp => kp.Value).ToList();
return new ClaimsPrincipal(new ClaimsIdentity(claimsCollection, "Custom"));
}
}
public class CustomAuthorisationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
string resource = context.Resource.First().Value;
string action = context.Action.First().Value;
if (action == "Show" && resource == "Code")
{
bool likesJava = context.Principal.HasClaim(ClaimStore._httpMyclaimsUsers, "True");
return likesJava;
}
else if (action == "Read" && resource == "Departments")
{
bool readDeps = context.Principal.HasClaim(ClaimStore._httpMyclaimsDepartments, "Read");
return readDeps;
}
return false;
}
}
How to implement these in a real world scenario without having too many IF conditions?
Try the following link , it seems like a decent solution
http://developers.axiomatics.com/blog/index/entry/custom-claims-based-authorization-in-net-using-axiomatics-pep-sdk-for-net.html
Also you can define your policy and load it
http://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthorizationmanager.loadcustomconfiguration.aspx
How to: Implement Claims Authorization in a Claims-Aware ASP.NET Application Using WIF and ACS
http://msdn.microsoft.com/en-us/library/gg185907.aspx
I finally managed to design my own system with the required functionality using the existing asp.net identity 2.0 tables + a few of my own.
I'm gonna call every AREA-CONTROLLER-ACTION trio as resources in my system. WebAPI included. Area itself is a resource. Controller itself is a resource. Action itself is a resource. Any combination of them, is also a resource. I'll auto generate everything from the system itself using reflection.
Also, I'm going to use the same AspNetRoles table to store my User Groups. Users belong to one or more groups (Super Admin, Admin, Agent, Client etc.).
Using the existing Role based model as a user group based model with claims, I could get it working.Super admins are on god mode. They can create lower level users/groups/assign permissions etc.
Users can have special permissions. For example, Everyone in Agent group is denied access to updating a hotel, but a special agent who might also be the owner of a hotel can be given specific access to updating only their hotel.
Since the entire access control system runs on MVC area-controller-action sets. No one initially has no access (including super admins) and we gradually define which parts the groups/users has access to. And we give super admins and admins exclusive access through a claim. Access to everywhere is denied by default.
Once I Auto generated the AREA-CONTROLLER-ACTION sets, I let the user select which group has access to which item.
When the user logs in, I get all the resources the current user has access to and store them as claims. Based on that, using a claims auth manager, when a user request access to some resource, I can check their claims and decide if they should be given access to.
foreach(var claim in permissionClaims) {
var parts = claim.Value.Split(new [] {
'|'
}, StringSplitOptions.None);
if (parts.Length == 3) {
//var httpMethod = parts[0];
var action = parts[1];
var api = parts[2];
//Current.Log.Warn("Checking Access : " + req + " [action: " + action + "]");
// is this request for a API action?
if (api.Contains("API")) {
// if so, req must be for a API action
if (req.Contains("Api") && action.Contains(req)) {
Log.Trace("User has access to API : " + req + " [action: " + action + "]");
return true;
}
} else {
// this is for a MVC action
if (action.Contains(req)) {
Log.Trace("User has access to MVC : " + req + " [action: " + action + "]");
return true;
}
}
}
}
I have explained the approach in detail here - ASP.NET MVC Fine Grained Identity & Access Control.
I would like to know the best practices for the role based access control with spring.
My requirements are,
I will have set of roles assigned to users say,
user1=admin, user2=expert
user1 will have the accesses write like
/admin/member-management
/admin/project-management
......
for user2....
/myproject1/*
so if user2 tries to access the url
/admin/member-management
will be redirect to authorization failure page.
The standard framework to use with Spring MVC is Spring Security. While it can be very complex, here's a minimal version of what you need: 4.2.2 A Minimal Configuration
In your case, the config would be something like this:
<http auto-config='true'>
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
</http>
Spring Security has the concept of roles but out of the box it does not have a concept of permissions. It does have a concept of ACLs but this ACLs are a lot more complicated than permissions, and they are tied to acting on specific objects, versus authorizing actions in general.
Take a look at Apache Shiro. It has roles and permissions that look very similar to what you gave as an example (using wildcards). It is also easy to use with Spring.
public class DashBoardController {
#Autowired
UserService userService;
private static final Logger logger = LoggerFactory.getLogger(DashBoardController.class);
#SuppressWarnings("unchecked")
#RequestMapping(value = PathProxy.DashBoardUrls.SHOW_DASHBOARD, method = RequestMethod.GET)
public String role(Locale locale, Model model) {
String userRole = null;
logger.info("dashboard Controller");
Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) SecurityContextHolder
.getContext().getAuthentication().getAuthorities();
for (SimpleGrantedAuthority simpleGrantedAuthority : authorities) {
userRole = simpleGrantedAuthority.toString();
}
switch (userRole) {
case "ROLE_ADMIN":
return "dashboard/admin";
case "ROLE_HR_MANAGER":
return "dashboard/hr_manager";
case "ROLE_MANAGER":
return "dashboard/manager";
case "ROLE_EMPLOYEE":
return "dashboard/employee";
case "ROLE_COMPANY_ADMIN":
return "dashboard/admin";
default:
break;
}
return userRole;
}
}