How to get the last login session details of a user in Keycloak using Keycloak rest endpoints? - keycloak

How to get the last login session details of a user in Keycloak using keycloak rest endpoints?
Example:
builder.append(OAuth2Constants.AUDIENCE+"="+clientId+"&");
builder.append(OAuth2Constants.GRANT_TYPE+"="+OAuth2Constants.UMA_GRANT_TYPE+"&");
headers.put("Content-Type", "application/x-www-form-urlencoded");
headers.put("Authorization", "Bearer "+accessToken);
//String keycloakURL = keyCloakCFGBean.getCreateRefreshSession();
String keycloakURL="http://10.10.8.113:10004/auth/realms/{realm}/protocol/openid-connect/token";
keycloakURL = keycloakURL.replace("{realm}", realmName);
URL url = new URL(keycloakURL);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setUseCaches(false);
httpURLConnection.setDoInput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
if (headers != null && headers.size() > 0) {
Iterator<Entry<String, String>> itr = headers.entrySet().iterator();
while (itr.hasNext()) {
Entry<String, String> entry = itr.next();
httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream(), StandardCharsets.UTF_8);
outputStreamWriter.write(builder.toString());
outputStreamWriter.flush();

So there are a couple of scenarios here. All of this information assumes that you have an appropriate bearer token that you are sending in the header of the request for authentication/authorisation, and requires that you have sufficient admin privileges in the Keycloak realm.
I've not gone into detail in terms of the precise code you write in a particular language, but hopefully the instructions are clear in terms of what you need your code to do.
Sessions
If you are interested in ACTIVE user sessions specifically, you can use the API endpoint as described at: https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_getsessions
That is:
GET /{realm}/users/{id}/sessions
e.g. the full URL would be:
https://{server}/auth/admin/realms/{realm}/users/{id}/sessions
In the response there will be a property called lastAccess that will contain a number that is the usual UNIX milliseconds since 1/1/1970. If you take that number, you can then parse it in your language of choice (Java from the looks of it?) to get the date/time in the format that you require.
All Logins
However I suspect what you really want is to look at the last login across all of the stored information in Keycloak, not just active user sessions, so for that you need to look for the Realm EVENTS. Note that Keycloak only stores events for a certain amount of time, so if it's older than that then you won't find any entries. You can change how long events are stored for in the events config page of the realm admin console.
To get all realm events you call the endpoint mentioned here: https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_getevents (Search for "Get events Returns all events, or filters them based on URL query parameters listed here" if the link doesn't take you straight there).
i.e.
GET /{realm}/events
e.g. the full URL would be: https://{server}/auth/admin/realms/{realm}/events
You will need to filter the results based on "type" (i.e. so that you only have events of type "LOGIN"), and if you want to check a specific user you would also want to filter the results on userId based on the ID of that user account.
You can perform both of these filters as part of the request, to save you having to get the full list of events and filter it client-side. To filter in the request you do something like the following:
https://{server}/auth/admin/realms/{realm}/events?type=LOGIN&user={id}
From the resultant JSON you can then get the result with the highest value of the time property, that represents that login event. The time property will be a UNIX time of milliseconds since 1/1/1970 again, so again you can convert this to a format that is appropriate to you once you have it.
Hope that's helpful!

use Keycloak rest Api
${keycloakUri}/admin/realms/${keycloakRealm}/users
and you will get a response as JWT. Decode it and you will get all the info related to the user.
OR you may use the java client API for example by
Keycloak kc = KeycloakBuilder.builder()
.serverUrl("https://localhost:8443/auth")
.realm("master")
.username("admin")
.password("admin")
.clientId("Mycli")
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build())
.build();
CredentialRepresentation credential = new CredentialRepresentation();
credential.setType(CredentialRepresentation.PASSWORD);
credential.setValue("test123");
UserRepresentation user = new UserRepresentation();
user.setUsername("testuser2");
user.setFirstName("Test2");
user.setLastName("User2");
user.setEmail("aaa#bbb.com");
user.setCredentials(Arrays.asList(credential));
user.setEnabled(true);
user.setRealmRoles(Arrays.asList("admin"));
UsersResource usersResource = kc.realm("my-realem").users();
UserResource userResource = usersResource.get("08afb701-fae5-40b4-8895-e387ba1902fb");
you will get the list of users. Filter by user ID then you will find all user info.

Related

Websphere Commerce Custom REST service for Login using social sign in not generating valid WC Tokens and CTXMGMT table not getting updated

In the current website, social login is implemented using the mapping in struts and it will call the custom controller command "XYZThirdPartyLoginCmdImpl" which will authenticate the details passed and it will call the out of the box "LogonCmd" for login.
For creating a REST service for the above functinality, created a custom REST handler " XYZThirdPartyLoginHandler" and from there called the existing command "XYZThirdPartyLoginCmdImpl" using the method executeControllerCommandWithContext. Once the response is generated, WCToken and WCTrustedToken is generated by the below code.
ActivityToken token = getActivityToken();
String identitySignature = token.getSignature();
String identityId = token.getActivityGUID().getGUID().toString();
Map<String, Object> identityTokenInfo = new HashMap();
identityTokenInfo.put(MemberFacadeConstants.EC_USERID, new String[] { userId.toString() } );
identityTokenInfo.put(MemberFacadeConstants.ACTIVITY_TOKEN_ID, new String[] { identityId } );
identityTokenInfo.put(MemberFacadeConstants.ACTIVITY_TOKEN_SIGNATURE, new String[] { identitySignature } );
Map<String, String> commerceTokens = CommerceTokenHelper.generateCommerceTokens(identityTokenInfo);
String wcToken = commerceTokens.get(CommerceTokenHelper.WC_TOKEN);
String wcTrustedToken = commerceTokens.get(CommerceTokenHelper.WC_TRUSTED_TOKEN);
The tokens generated using this is not valid. If we try to invoke any other rest service using this token it shows invalid user session error. "XYZThirdPartyLoginCmdImpl" authentication is success as the userId returned is correct. After executing this the user context is not getting created in CTXMGMT table.
Please guide on how to generate the valid tokens in REST flow in this use case.
If you are on v9, you might want to investigate the oauth_validate REST call (/wcs/resources/store//loginidentity/oauth_validate). See the KC article for more information: [https://www.ibm.com/support/knowledgecenter/SSZLC2_9.0.0/com.ibm.commerce.integration.doc/tasks/tcv_sociallogin.htm][1]. This calls some different commands (OAuthTokenValidationCmdImpl and OpenUserRegisterCmd) than what you might be using, but it allows you to pass in a 3rd party token, and it generates the right tokens.

SharePoint Search REST API with bearer token returns wrong number of items

I have an EXTREMELY strange issue with the search.
I am doing a query by using a GET on
https://sonar-sandbox.gredspdev.loc/_api/search/query?querytext='DMSSonarDocId:5042aa1f-b3a4-4577-8e21-8a47ca27c243 OR DMSSonarDocId:1401144b-bd3d-429a-a386-5061ecc714e1'&sourceid='a0f4d450-e701-4f2a-888a-8d871002752d'&trimduplicates=false&rankingmodelid='05289DBE-73E9-4665-BF69-EE68274176EB'&rowlimit=9000&enablestemming=false&enablesorting=false&selectproperties='DMSSonarDocId,<...>'
I am authenticating using a bearer token generated for my user. This query returns 7 items. Then I am executing THE SAME URL in my browser with my user (NTLM) and it returns 10 items. That is not all. I generate the token for my user one more time. Paste it to the previous GET request with a bearer token and it returns 10 items... I am waiting few seconds, lets say 30... GET one more time and I have 7 items returned (always the same)! And this is 100% replicable. After another GET from the browser and regeneration of the token 10 items, after some time on the same token 7 items....
Update. I have found difference in logs in ULS:
When working correct:
Context has no SMTP/UPN claims. IdentityContext: '{"nameid":"s-1-5-21-2843295230-2675739751-2774624307-1482","nii":"urn:office:idp:activedirectory","upn":"kowalj#spdev.loc","userId":"0#.w|spdev\\kowalj","appliesTo":"https:\/\/sonar-sandbox.spdev.loc\/"}'
When not working correct:
Context has no SMTP/UPN claims. IdentityContext: '{"nameid":"s-1-5-21-2843295230-2675739751-2774624307-1482","nii":"urn:office:idp:activedirectory","upn":"spdev\\kowalj","userId":"0#.w|spdev\\kowalj","appliesTo":"https:\/\/sonar-sandbox.spdev.loc\/"}'
ANOTHER FINDINGS:
Missing items are those which are assigned to me directly - not through group resolved by our custom claims provider - yes, we have a custom claims provider which worked ok for a long time (we were using only NTLM authorization).
We are sending those claims:
new Claim[]
{
new Claim("nameid", sid),
new Claim("nii", Constants.Auth.Token.IdentityIssuer)
};
ANOTHER FINDINGS:
When everything work correctly, executing this code in the SP farm solution in some REST proxy: ((ClaimsIdentity)HttpContext.Current.User?.Identity).Claims.FirstOrDefault(c => c.ClaimType.EqualsIgnoreCase(ClaimTypes.Upn)) returns upn.
When the search is not working, the same code returns null... And as I said, I can refresh the page and at the beginning the upn is there and after some time it is not...
I have found a work around. Not very good but I do not see any other option for now.
We have started Claims to Windows Token Service and if user does some requests to our app, we do (from time to time) requests to our custom proxy placed in the SharePoint farm solution to simulate using SharePoint by that user by using normal windows authentication:
public void RefreshUpn()
{
WindowsImpersonationContext _wic = null;
try
{
string login = HttpContext.Current.User.Identity.Name;
login = login.Substring(login.LastIndexOf('|') + 1);
string[] loginParts = login.Split('\\');
string loginForUpnLogon = Culture.Invariant($"{loginParts[1]}#{loginParts[0]}");
WindowsIdentity wi = S4UClient.UpnLogon(loginForUpnLogon);
if(wi == null)
{
throw new InvalidOperationException(Culture.Invariant($"Could not impersonate user '{HttpContext.Current.User.Identity.Name}'."));
}
_wic = wi.Impersonate();
using (var wc = new WebClient())
{
wc.UseDefaultCredentials = true;
var requestUrl = HttpContext.Current.Request.Url;
wc.DownloadString(requestUrl.Scheme + "://" + requestUrl.Host + "/_api/web/currentuser");
}
}
finally
{
_wic?.Undo();
}
}
After such request, SharePoint responses to us correctly for around 150 seconds.

[orientdb]: get the current user when authenticating with tokens

How can i get the rid of the current user (OUser) via the binary api. I am using the inbuilt token based authentication.
I would expect two approaches:
a function like currentUserRID() or something. I looked in the documentation but found nothing.
decrypting the token to unlock the userId/name. I tried this approach but couldn't manage to. I looked here: https://github.com/orientechnologies/orientdb/issues/2229 and also https://groups.google.com/forum/#!topic/orient-database/6sUfSAd4LXo
I find your post just now, may be is too late but you can do like this:
OServer server = OServerMain.create(); // for exemple
ODatabaseDocumentTx db = new ODatabaseDocumentTx(BDDURL).open("admin","admin"); // admin is juste for this exemple
OTokenHandlerImpl handler = new OTokenHandlerImpl(server);
OToken tok = handler.parseWebToken(yourtoken);
OUser user = tok.getUser(db);

Facebook Private Messaging

It is said, that it is not possible to initiate new conversation through the API alone, except using Facebook's own Form integrated in the app. Is this correct, or is there some new API, which enables me to initiate a new conversation?
To reply to an existing conversation, I retrieved the conversations id using the following FQL Query "SELECT thread_id, . WHERE viewer_id={0} AND folder_id=0". Afterwards I retrieved the PageAccessToken for my app page using my user Access token, and tried to use this call:
*You can reply to a user's message by issuing an HTTP POST to /CONVERSATION_ID/messages with the following parameters [conversation id, message]. A conversation ID look like t_id.216477638451347.*
My POST Call looked like this (this is not a valid thread id): /t_id.2319203912/messages with message parameter filled. But it always said "Unknown method". Can you help me out with this one? Is there a parameter missing? I passed in the page's Access Token to call this one.
Is there some API out (except Facebook's Chat API), that I am missing, which can send private messages to users?
Edit:
What I wonder about is, that the code below only returns a single page, the application's page. Is this correct, or is there another page token required? This is what bugged me the most about the returned page.
The FacebookClient uses my UserToken to perform the next following task.
This is the code to retrieve my Page Access Token:
dynamic pageService = FacebookContext.FacebookClient.GetTaskAsync("/"+UserId+"/accounts").Result;
dynamic pageResult = pageService.data[0];
_pageId = pageResult["id"].ToString();
return pageResult["access_token"].ToString();
Now the code to retrieve my ConversationÍd:
dynamic parameters = new ExpandoObject();
parameters.q = string.Format("SELECT thread_id, folder_id, subject, recipients, updated_time, parent_message_id, parent_thread_id, message_count, snippet, snippet_author, object_id, unread, viewer_id FROM thread WHERE viewer_id={0} AND folder_id=0", FacebookContext.UserId);
dynamic conversations = FacebookContext.FacebookClient.GetTaskAsync("/fql",parameters).Result;
The following code is executed using the access token retrieved from the code above (page access token request).
Now the Code used to send the reply:
dynamic parameters = new ExpandoObject();
parameters.message = CurrentAnswer;
string taskString = "/t_id." + _conversationId + "/messages";
dynamic result = FacebookContext.FacebookClient.PostTaskAsync(taskString,parameters).Result;
return true;
I also tried it with facebook's graph API Debugger using the token, which is returned by my first part of code. But with the same error message.

Retrieve User ID of Facebook App Invitor

In the context of a given Facebook app, suppose User A invited user B to start using it. Once User B accepts to use the app, is there any way to retrieve the ID of User A programmatically (via either PHP/JS SDK) ? This doesn't seem quite documented.
For what it's worth, A/B users are friends, if it's any use.
when user comes following the app request, you can get request id's using
$_GET['request_ids']
then retrieve all the request ids with which you can call graph api to get the corresponding request details like below:
if(isset($_GET['request_ids']))
{
$request_ids = $_GET['request_ids'];
}
$request_ids = explode(",", $request_ids);
foreach($request_ids as $request_id)
{
$request_object = $facebook->api($request_id);
//this $request_object have sender facebook id in the field uid_from
}
If you look here:
http://developers.facebook.com/docs/reference/dialogs/requests/
You can see the object layout. Of note is the data property:
Optional, additional data you may pass for tracking. This will be
stored as part of the request objects created. The maximum length is
255 characters.
In this object you can add your referring UserId and then when the request is claimed, you can then process it on your end.
Hope this helps.