Keycloak Custom User Storage Provider (assigned roles set / effective roles empty) - keycloak

I am writing a custom UserStorageProvider for Keycloak against a HTTP-Service which contains only user information but no role information.
I want to accomplish that all users from this service are assigned to a composite role which is already existent in keycloak. As you can see I am resolving the the aggregated roles for composite role manually which is not really keen.
Main problem is, that the roles I assign here in the following AbstractUserAdapter are visible in the admin console in Keycloak under "assigned roles" but not in the "effective roles". Consequently they are not mapped into my bearer token.
#Override
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
Set<RoleModel> result = new HashSet<>();
for (RoleModel role : app.getRoles()) {
if("my_keycloak_comp_role".equals(role.getName())) {
result.add(role);
if (role.isComposite()) {
result.addAll(role.getComposites());
}
}
}
return result;
}

Related

Keycloak custom user federation with user attributes

I have implemented a custom UserStorageProvider with AbstractUserAdapter for Keycloak for retrieving users from external DB and login users with credentials stored in that DB. All works ok and the data is read only via Keycloak admin panel.
I wanted to add additional attributes to users from data stored in external DB, I would like to add this data to the token via Attribute Mapper, is there a way to do it? Or do II need to implement AbstractUserAdapterFederatedStorage? The problem with the later is that it is not read only and allows to edit the user data transferred to the keycloak user store.
It really depends on your implementation. If you have access to desired data for attributes and to the user, you can simply assign new attributes to him, i.e:
KeycloakSession session = // get session somewhere
RealmModel currentRealm = session.getContext().getRealm();
UserModel user = getUserSomehow(session, currentRealm);
user.setSingleAttribute("attributeName", "attributeValue");
...
private UserModel getUserSomehow(KeycloakSession session, RealmModel realm) {
return KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), "<username>");
// or (cached model):
// return session.users().getUserById("<userId>", realm);
// or (Un-cached model):
// return session.userStorageManager().getUserById("<userId>", realm);
}

how to set Internal/Subscriber role as default role to all authenticated users in WSO2 Api manager?

i am trying to give default role as Internal/Subscriber to all users.
i made changes in we made changes in file /_system/config/apimgt/applicationdata/tenant-conf.json and added role such as to Internal/creator,Internal/everyone,apimrole
"Name": "apim:subscribe",
"Roles": "admin,Internal/creator,Internal/everyone,apimrole,Internal/subscriber"
it gives me below error
org.wso2.carbon.apimgt.api.APIManagementException: Error while adding the subscriber
laxman#gmail.com#carbon.super#carbon.super
any help appreciated
New user creation takes place in the WSO2 API Manager in two ways.
Through the management console of the API Manager
Self signup
In 1st way you can assign roles when creating users.
For self signed-up users there already exists a handler to assign Internal/subscriber role to the new users who are having Internal/selfsignup role.
To assign role: Internal/subscriber to new users or existing role not assigned users we have below two options:
Option 1
If you wish to assign subscriber role to existing role not assigned users using Management Console, then you can go to roles listing page there:
There is an option: Assign Users in Actions column in role list relevant to Internal/subscriber role.
It will list all the users who have not assigned Internal/subscriber role and there are several options to select many users at once and assign the role.
Option 2
You can write a custom user operation event listener and add it as OSGI bundle.
In this case you can refer this WSO2 IS doc and write a event listener extending AbstractIdentityUserOperationEventListener.
This sample code worked for me:
public class SampleEventListener extends AbstractIdentityUserOperationEventListener {
private static final String EVENT_LISTENER_TYPE = "org.wso2.carbon.user.core.listener.UserOperationEventListener";
private static final String SUBSCRIBER_ROLE = "Internal/subscriber";
#Override
public boolean doPreAddUser(String userName, Object credential, String[] roleList, Map<String, String> claims,
String profile, UserStoreManager userStoreManager) throws UserStoreException {
List<String> roles = new ArrayList<>(Arrays.asList(roleList));
if (!roles.isEmpty() && !roles.contains(SUBSCRIBER_ROLE)) {
userStoreManager.updateRoleListOfUser(userName, new String[]{}, new String[] { SUBSCRIBER_ROLE });
}
return true;
}
This will add Internal/subscriber role to each newly adding user, if the user doesn't have that role in the process of adding new user.
Here it has mentioned multiple interfaces with which you can implement User Store Listeners.
For OSGI bundle creation and deployment process you can find this sample GitHub project. You can copy the built jar file to the directory <APIM_HOME>/repository/components/dropins/ by following the steps have been mentioned there. (Since WSO2 API Manager is also using WSO2 IS components you can follow the same steps mentioned in README with the API Manger as well)
You can go through this blog post to get complete idea about OSGI bundling.

How can the resource server identify the resource owner using token in oauth2?

The typical scenario I am looking into is:
User1 provides proper credentials to the front-end rest client (grant type: password) and the client gets the token in return.
The client sends the token and accesses the resources owned by User1.
In my scenario, once the client has the access token for user1, I want the client to have access limited to User1's resources only.
Consider that the client accesses the URI /users/1/books. The response will contain all the books associated with User1. The main problem is that if the client accesses the URL /users/2/books with User1's token, it gets the list of all the books for User2 which shouldn't be allowed.
How can I limit the scope to the user whose credentials were used to obtain the token?
How can I map the token to a specific user in my resource server?
I am using Spring/Java. But any general theory will also help.
After a lot of debugging, I got the answer.
Spring security 1.4
Token store: InMemoryTokenStore()
In ResourceServerConfiguration, configure HttpSecurity.
#Override
public void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests().
// antMatchers("/oauth/token").permitAll().
antMatchers("/api/users/{userId}").access("#webSecurity.checkUserId(authentication,#userId)")
.anyRequest().authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();
// #formatter:on
}
Create a class WebSecurity and provide the implementation.
public class WebSecurity {
public boolean checkUserId(Authentication auth, int id) {
return ((UmUser)auth.getPrincipal()).getId() == id;
}
}
Resources:
http://docs.spring.io/spring-security/site/docs/current/reference/html/el-access.html#el-access-web-path-variables
http://www.baeldung.com/get-user-in-spring-security
I had to debug a lot as I was using JwtTokenStore. This returned the Principal as a String and not the instance of UserDetails as I was expecting.
Once I switched to InMemoryTokenStore, I got the expected results. This was not a problem for me as I had the choice, but I would still like to know how to achieve it with the JWT.

grails spring-security create user

Im having some problems creating new user from one of my controllers. I'm trying to add a new user to my MongoDB user collection like this. Authorities is defined as a Set of Role in the domain.
Role role = new Role(authority:"ROLE_USER")
User user = new User(username:params.username,email:params.email,password:params.password,enabled:params.enabled,
accountExpired:params.accountExpired,accountLocked:params.accountLocked,passwordExpired:params.passwordExpired,
authorities:[role])
if (user.validate()) {
user.save(flush:true)
} else {
user.errors.allErrors.each { println it }
}
The exact same code is able to create a user successfully from the bootstrap, but when i'm trying to do the same thing from a simple controller i'm getting this error:
2012-09-24 10:43:27,450 [http-8080-3] ERROR binding.GrailsDataBinder - Unable to auto-create type interface java.util.Set, class java.lang.InstantiationException thrown in constructor
a:662)
Looks like the problem is with data binding. You have to create User with authorities first and then add role using UserRole domain. Something like:
Role role = Role.findByAuthority("ROLE_USER")
User user = new User(username:params.username,email:params.email,password:params.password,enabled:params.enabled, accountExpired:params.accountExpired,accountLocked:params.accountLocked,passwordExpired:params.passwordExpired)
new UserRole(user: user, role: role).save(flush: flush, insert: true)
user.save(flush:true)
For more information how to create user with spring security, you may want to look at Spring Security UI

ASP.NET MVC 2 Authorization Regex

What i currently have is the following:
namespace AzureCCCMVC.Controllers
{
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
//Stuff
}
}
what I want to do is have roles for each client such as
Roles { "DEMOAdmin", "GOOGAdmin" , "MSFTAdmin" }
and be able to Authorize The Client name (from URL) and in that role
I know I am doing a horrible job of explaining this... It is possible that I can have users that are users of several clients but only admin's of one ...
I am not sure if i understand exactly what you try to achive, but i guess you are heading in wrong direction. What would prevent you from just having roles independend from the client and store to which client an admin belongs to:
admin1 -> GOOG
admin2 -> MSFT
With this information just use [Authorize(Roles="Admin")] and show the user only data that belongs to his organisation:
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
var data = GetDataForDomain(); //retreive data based on organisation of the user
}