How can I get user roles from current session? - java

After login in my system with Keycloak I want to get the user role-mappings(defined on keycloak admin console) from the user I'm logged in.
I'm able to get the First Name, Last Name, Id, token-id, but when trying to get the roles I get an empty array:
private List<KeycloakOidcProfile> getUserData() {
final PlayWebContext context = new PlayWebContext(ctx(), playSessionStore);
final ProfileManager<KeycloakOidcProfile> profileManager = new ProfileManager(context);
System.out.println("Roles->>>"+ profileManager.get(true).get().getRoles()); //here i get -> []
System.out.println("FirstName->>>"+ profileManager.get(true).get().getFirstName());
System.out.println("Last Name->>>"+ profileManager.get(true).get().getFamilyName());
System.out.println("ID->>>"+ profileManager.get(true).get().getId());
return profileManager.getAll(true);

I believe that, you should implement your own AuthorizationGenerator and attach it to the client (to Keycloak client in this case) in order to map token roles to
KeycloakOidcProfile, but be sure that OIP sends the roles in his token.
There is some glue http://www.pac4j.org/docs/clients.html

Related

Azure Select Account shown when user already logged in session

We've migrated from adal4j to msal4j in our java web applications.
All works well but the big difference is that when the user is already logged (maybe in other applications but same browser session) we always see the "select user" page and the user is not logged automatically and redirected to redirect uri as before with adal4j.
This is how we redirect to autentication page:
private static void redirectToAuthorizationEndpoint(IdentityContextAdapter contextAdapter) throws IOException {
final IdentityContextData context = contextAdapter.getContext();
final String state = UUID.randomUUID().toString();
final String nonce = UUID.randomUUID().toString();
context.setStateAndNonce(state, nonce);
contextAdapter.setContext(context);
final ConfidentialClientApplication client = getConfidentialClientInstance();
AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
.builder(props.getProperty("aad.redirectURI"), Collections.singleton(props.getProperty("aad.scopes"))).responseMode(ResponseMode.QUERY)
.prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
contextAdapter.redirectUser(authorizeUrl);
}
I've tried to remove .prompt(Prompt.SELECT_ACCOUNT)
but I receive an error
Any ideas?
• You might be getting the option for selecting the user account after switching to MSAL4J in your browser even after the SSO is enabled because either clearing the token cache is enabled in your code or MsalInteractionRequiredException option is thrown and specified accordingly due to which the application asks for a token interactively.
Thus, please check which accounts information is stored in the cache as below: -
ConfidentialClientApplication pca = new ConfidentialClientApplication.Builder(
labResponse.getAppId()).
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
build();
Set<IAccount> accounts = pca.getAccounts().join(); ’
Then, from the above information, if you want to remove the accounts whose prompts you don’t want to see during the user account selection such that the default account should get selected and signed in automatically, execute the below code by modifying the required information: -
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
• And for the MsalInteractiveRequiredException class in the code, kindly refer to the below official documentation link for the AcquireTokenSilently and other reasons responsible for the behaviour. Also, refer to the sample code given below for your reference regarding the same: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-error-handling-java#msalinteractionrequiredexception
IAuthenticationResult result;
try {
ConfidentialClientApplication application =
ConfidentialClientApplication
.builder("clientId")
.b2cAuthority("authority")
.build();
SilentParameters parameters = SilentParameters
.builder(Collections.singleton("scope"))
.build();
result = application.acquireTokenSilently(parameters).join();
}
catch (Exception ex){
if(ex instanceof MsalInteractionRequiredException){
// AcquireToken by either AuthorizationCodeParameters or DeviceCodeParameters
} else{
// Log and handle exception accordingly
}
}

How to copy an existing organisation role in Liferay and add it to Users that already had the original role?

So i am working with Liferay 7/Oracle 11g and i try to copy existing organization roles of a specified subtype, rename them and then add those new roles to users that had the original Roles.
So getting roles by subtype works pretty straightforward,
the first Problem arises after i add the new role, i receive an error message when trying to view the new Role:
Someone may be trying to circumvent the permission checker: {companyId=20115, name=com.liferay.portal.kernel.model.Role, primKey=31701, scope=4}
the second Problem is getting the Users that have the original Organization Role as i can't find an existing Liferay class that delivers me that Information. From what i know its saved withing the USERGROUPROLE table, so i could read it from there with my own SQL select, but i would prefer if there was a Liferay class that provided that information.
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
long roleId = CounterLocalServiceUtil.increment();
Role newRole = RoleLocalServiceUtil.createRole(roleId);
newRole.setClassPK(roleId);
newRole.setCompanyId(role.getCompanyId());
newRole.setUserId(role.getUserId());
newRole.setUserName(role.getUserName());
newRole.setClassName(role.getClassName());
newRole.setTitle(role.getTitle());
newRole.setDescription(role.getDescription());
newRole.setCreateDate(new Date());
newRole.setType(role.getType());
newRole.setName(replaceOrAppendYear(role.getName(), newYear));
newRole.setSubtype(String.valueOf(newYear));
RoleLocalServiceUtil.addRole(newRole);
//assign Users that have base Role, the new Role
long[] aUserId = UserLocalServiceUtil.getRoleUserIds(role.getRoleId());
for(long userId : aUserId) {
RoleLocalServiceUtil.addUserRole(userId, newRole.getRoleId());
}
}
UPDATE:
I fixed the first problem by using another addRole method of UserLocalServiceUtil, code is now as following:
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
Role newRole = RoleLocalServiceUtil.addRole(role.getUserId(), Role.class.getName(),
CounterLocalServiceUtil.increment(), replaceOrAppendYear(role.getName(), newYear),
role.getTitleMap(), role.getDescriptionMap(), role.getType(),
String.valueOf(newYear), null);
//add User from base Role to new Role
long[] aUserId = UserLocalServiceUtil.getRoleUserIds(role.getRoleId());
//aUserId still empty
for(long userId : aUserId) {
RoleLocalServiceUtil.addUserRole(userId, newRole.getRoleId());
}
}
So the Problem of getting all User that have a certain Organization Role still exists.
So my solution to my problems is as following, i used the other addRole method to add a new Role and that also creates the additional entry in the db so there is no error message anymore.
On my second problem, i just use the liferay API to get all entries from UserGroupRole Table and then i filter all the entries via the roleId that i need. Not a nice solution, but in my case even with tens of thousands of entries (and thats generous for what i work on) the function will be called once a year so ¯\_(ツ)_/¯
So here is the solution:
List<Role> lRole = RoleLocalServiceUtil.getSubtypeRoles(String.valueOf(adoptFromYear));
for(Role role : lRole) {
Role newRole = RoleLocalServiceUtil.addRole(role.getUserId(), Role.class.getName(),
CounterLocalServiceUtil.increment(), replaceOrAppendYear(role.getName(), newYear),
role.getTitleMap(), role.getDescriptionMap(), role.getType(), String.valueOf(newYear), null);
//get all User - Group (Organization) - Role Objects and filter by Role
List<UserGroupRole> lUserGroupRole = UserGroupRoleLocalServiceUtil
.getUserGroupRoles(QueryUtil.ALL_POS, QueryUtil.ALL_POS).stream()
.filter(ugr -> ugr.getRoleId() == role.getRoleId()).collect(Collectors.toList());
//add new Role to all existing Users that had the adopted role
long[] roleIds = {newRole.getRoleId()};
for(UserGroupRole ugr : lUserGroupRole) {
UserGroupRoleLocalServiceUtil.addUserGroupRoles(ugr.getUserId(), ugr.getGroupId(), roleIds);
}
}

Synchronize REST endpoint to wait for 2 calls with same parameter

I am creating an application in which two players should have an opportunity to compete with each other in writing code.
For example, for now one player can initiate a session creation:
#PostMapping("/prepareSession")
public UUID prepareSession(#RequestParam("taskName") String taskName) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();
User playerOne = userService.findOne(currentPrincipalName);
Task task = taskService.findOne(taskName);
UUID sessionId = UUID.randomUUID();
sessionService.save(new Session(sessionId, playerOne, null, task));
return sessionId;
}
Then, this session id he needs to send to a player who he wants to compete.
And then second player inputs sessionId and gets a task description.
#GetMapping("/connect")
public Task connect(#RequestParam("sessionId") String sessionId) throws InterruptedException {
Session session = sessionService.findOne(sessionId);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();
User playerSecond = userService.findOne(currentPrincipalName);
session.setPlayerSecond(playerSecond);
sessionService.save(session);
return session.getTask();
}
I wonder how to make the rest endpoint to wait until both players with same sessionId calls it and then notify them with the task description.
I want them to write code within a one session, with a one code timer.
Please suggest how I should do that
What you are looking for can be achieve like this
You could use a DeferredResult result and store it in a map until a user with the same sessionId joins. Ex
Map<String, DeferredResult<ResponseEntity<?>>> unconnected = new HashMap<String, DeferredResult<ResponseEntity<?>>>();
User one would call the connect prepareSessionAPI to receive the sessionId
User one would then call the connect API. The connet api would store this request/defferred result in the hashmap until user 2 joins. Ex
DeferredResult<Task> unconnectedTask = new DeferredResult<Task>();
unconnected.put(sessionId, unconnectedTask);
Now, user one's request would be stored in an in memory map until user two joins
User one would send the sessionId to user two
User two would call the connect API. The connect API would look for the session in the HashMap, and if it exists, it would perform the operations needed, then set the result of the deferred result. Ex
DeferredResult<Task> unconnectedTask = unconnected.get(sessionId);
if(unconnectedTask != null) {
// Do work
unconnectedTask.setResult(task);
} else {
// This is user one's request
}
Please note, this is pseudo code.
put this code both of method,
please import spring transnational jar
#Transactional(propagation =Propagation.REQUIRED,isolation=Isolation.SERIALIZABLE,readOnly=false,transactionManager="transactionManager")
if any issue inform

Bing ads Campaign Management

I have recently started playing with the Bing Ads api for managing my ads and campaigns and I am having problem in authenticating user (not oauth authentication).
I authenticated my user using oauth by the following
private String devToken = "ZZZZZ";
private String clientId = "AAA0BBB-XXXX-AAAAA";
protected static String UserName = "a.v#h.c";
protected static String Password = "********";
// To get the initial access and refresh tokens you must call requestAccessAndRefreshTokens with the authorization redirection URL.
OAuthTokens tokens = oAuthDesktopMobileAuthCodeGrant.requestAccessAndRefreshTokens(url);
System.out.println("Access token: " + tokens.getAccessToken());
System.out.println("Refresh token: " + tokens.getRefreshToken());
authorizationData = new AuthorizationData();
authorizationData.setDeveloperToken(getDevToken());
authorizationData.setAuthentication(oAuthDesktopMobileAuthCodeGrant);
This authenticates my user just fine since I can use the ICustomerManagementService.class just fine for accounts related information
customerServiceClient = new ServiceClient<>(authorizationData, ICustomerManagementService.class);
ArrayOfAccount accounts = searchAccountsByUserId(user.getId());
The above works perfectly. But when I try to do the same with ICampaignManagementService.class like below
campaignServiceClient = new ServiceClient<>(authorizationData, ICampaignManagementService.class);
GetAdsByAdGroupIdRequest cReq = new GetAdsByAdGroupIdRequest();
cReq.setAdGroupId(1234567890L);
campaignServiceClient.getService().getAdsByAdGroupId(cReq);
I get error code 106 saying that the user is not authorized.
The user does not represent a authorized developer.
106
Any help in this regard ?
Please try to set the CustomerId and CustomerAccountId header elements (CustomerId and AccountId of AuthorizationData). These headers are not available with the Customer Management service, but are applicable for Campaign Management service. If that does not resolve the issue please feel free to send the SOAP request + response to support for investigation. I hope this helps!

How to accept buddy request properly in Android smack?

There is a openfire server and Android clients (smack). All clients can add each other to buddy/roster list (without authorization, I want user can see each other without accept buddy request). I have some problems of getting the Presence information of the buddy request sender.
Assume there are 2 users - User A, User B.
I can add User B to User A's Roster by:
Roster roster = xmppManager.connection.getRoster();
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
roster.createEntry("userB", "userB#abc.com", null);
I can see User B at User A's roster list. Everything is fine so far
There are few problems with User B. I state what is the problem at the code below:
//I have set the available and status of User A by:
//xmppManager.setStatus(available, bundle.getString("new_status"));
...
// That's how I get Roster and Presence of user A
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
Presence presence = roster.getPresence(entry.getUser());
// User A always not available even I set User A to available
Log.e(TAG, "presence.isAvailable() = " + presence.isAvailable());
// User A's status always empty
Log.e(TAG, "presence.getStatus() = " + presence.getStatus());
// User A's getName() always null
if (entry.getName() != null)
{
name = entry.getName();
}
else
Log.e(TAG, "GetName is null");
}
Do I need to createEntry() at User A? Or do I need to do something with the buddy request like this?
#Override
public void entriesAdded(Collection<String> collection) {
String user = "";
Iterator<String> it = collection.iterator();
if(it.hasNext()){
user=it.next();
}
Presence presence = new Presence(Presence.Type.subscribe);
presence.setTo(user);
connection.sendPacket(presence);
}
But it does not work. It seems that I need to do something to user B first. Any idea is welcome, thanks!
Okay, I toiled hard at this for a couple of days and finally got things working. I have implemented it with a manual subscription mode (ie. user needs to accept another user's request manually). There is no need to create entries yourself as the server handles this automatically according to the presences sent/received.
For your case (automatic subscription), simply send a subscribe and subscribed presence immediately instead of saving the request locally.
This is how it works:
User1 sends subscribe presence to User2.
Roster entry gets automatically created in User1's roster (but not in User2's roster).
User2 receives subscribe request from User1.
User2 sends back a subscribed presence to User2 (User2 > User1 subscription complete).
User2 checks if User1 is in User2's roster. User1 is not in User2's roster. User2 sends back a subscribe presence to User1.
Roster entry gets automatically created in User2's roster.
User1 receives subscribe presence from User2.
User1 checks if User2 is in User1's roster. User2 is in User1's roster. User1 sends back a subscribed presence to User2 (User2 > User1 subscription complete).
final Presence newPresence = (Presence) packet;
final Presence.Type presenceType = newPresence.getType();
final String fromId = newPresence.getFrom();
final RosterEntry newEntry = getRoster().getEntry(fromId);
if (presenceType == Presence.Type.subscribe)
{
//from new user
if (newEntry == null)
{
//save request locally for later accept/reject
//later accept will send back a subscribe & subscribed presence to user with fromId
//or accept immediately by sending back subscribe and unsubscribed right now
}
//from a user that previously accepted your request
else
{
//send back subscribed presence to user with fromId
}
}

Categories

Resources