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

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.

Related

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

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.

How to Identify caller when grant_type is client_credentials?

I have ASP.NET Web application and I am using IdentityServer3 for user authentication. Our customers login to web application using userid/password.
Now I have one more Web API and some of our customers need to call this web api from their applications. (server to server communication). So based on this, in identityserver i did the following
1> Created a new scope name api
2> Created a new client for Web API and configured with allowed scope api and offline_access
3> Set flow to ClientCredentials
4> Set AccessTokenType to Jwt
5> For each customer i created different secret key
Now our customers can get access token at connect/token endpoint and then make call to API using the access token. The API validates the token with IdentityServer, and then returns the result. All good till here.
However, in API project i also need to identify the customer aka caller. Based on customer i need to do some logic
public class ResourcesController : ApiController
{
public IHttpActionResult Get()
{
var caller = User as ClaimsPrincipal;
// need to identify caller here
return Json(new
{
message = "OK",
});
}
}
(One option i can think of is taking customer id is as part of API url. Something like http://api.domain.com/v1/customerid/resources)
Is there anyway to make a use of IdentityServer to identify customer?
I've actually had a similar need some time ago. For the simplest solution, you should be able to assign a custom claim to each of the Identity Server client that you have created for your customers.
AlwaysSendClientClaims = true,
Claims = new List<Claim>()
{
new Claim("CustomerId", "0121021")
}
These client claims will then be included in the access token and therefore available to you in your backend.
public class ResourcesController : ApiController
{
public IHttpActionResult Get()
{
var caller = User as ClaimsPrincipal;
// need to identify caller here
var customerId = caller?.Claims.Where(p => p.Type.Equals("CustomerId")).First().Value;
// need to identify caller here
return Json(new
{
message = "OK",
});
}
}

Servicenow Rest API call to check if credentials are valid

I am calling ServiceNow Rest API for tables in my application. I allow the user to enter their servicenow instance credentials and domain url in my application.
I want to know if there is a Simple API call which I can make to ensure that the credentials entered are valid.
Currently I am making a call to get sys_user table and making the check.
This call seems to take more time. Is there a simpler REST URL which I can use here?
public static HttpConnectionResponse checkConnection(String host, String username, String password) {
String CHECK_URL = "/api/now/table/sys_user";
HttpConnectionResponse response = new HttpConnectionResponse();
String completeUrl = "https://"+host+CHECK_URL;
HashMap<String, String> requestHeaders = ConnectionUtils.getDefaultInputHeader();
Credential credential = ConnectionUtils.populateCredentials(username, password);
try{
response = HttpConnectorClient.getMethod(completeUrl, requestHeaders, credential);
}
catch(Exception e){
e.printStackTrace();
}
return response;
}
Why not just use any table or record that you've set to be accessible to any authenticated user, then make a REST API call with their credentials as the basic authentication credentials, to that resource? If you get the record rather than "access denied", the creds are valid. :-)
You could even make a simple UI page, or better yet, a Processor, just for that purpose.

Indico API Wrapper For Java Returning Key Not Found

I'm attempting to use indico's sentiment analysis api, I've debugged and inspected the "indico" object, and confirmed the correct api key is stored within it. I am also able to make calls to the API using curl from terminal, so I don't believe its my network settings (unless its something java specific?).
The code:
public double querySentiment(String qsent) throws UnsupportedOperationException, IOException, IndicoException{
double response = 0;
indico = new Indico(apikey);
IndicoResult single = indico.sentiment.predict(qsent);
log.inf("QUERY SEND SUCCESSFUL");
response = single.getSentiment();
log.inf("QUERY RECEIVE SUCCESSFUL");
return response;
}
The exception:
java.lang.IllegalArgumentException: API key not found. To use our API, sign up for a free account and api key at http://indico.io/register.
Wrong code snippet is given on indico API site. You have to pass key in params as well while making an indico object. Below code will work.
HashMap<String,String> params = new HashMap<String,String>();
params.add("api_key",apikey);
indico = new Indico(apikey,params);

Using OAuth with SforceServiceLocator

I'm looking at some code which is using the Salesforce SOAP API to create a session and access data:
SoapBindingStub binding = (SoapBindingStub) new SforceServiceLocator().getSoap();
String username;
String password;
[...]
LoginResult result = binding.login(username, password);
binding._setProperty(SoapBindingStub.ENDPOINT_ADDRESS_PROPERTY,result.getServerUrl());
SessionHeader sh = new SessionHeader();
sh.setSessionId(result.getSessionId());
binding.setHeader(new SforceServiceLocator().getServiceName().getNamespaceURI(), "SessionHeader", sh);
Given that I've got an OAuth access token and endpoint, is there a way to adapt this to work correctly without a username/password?
After a lot of trial and error -- the answer appears to be the following
Use the OAuth Access token as the sessionID
The ENDPOINT_ADDRESS_PROPERTY is the Endpoint URL and a SOAP API URL, eg: https://na15.salesforce.com/services/Soap/u/21.0