How to maintain same session across multiple requests in rest-assured? - rest

Pre-req:Rest-assured api tests with Java
Step
1. Launch URL and get login ticket - code snippet below to get login ticket
RestAssured.baseURI = "https://ve4al10p:453";
RestAssured.useRelaxedHTTPSValidation();
Response res =
given().
header("Content-Type","application/json").
when().
post("/i/login?action=lt").
then().
assertThat().statusCode(200).
extract().response();
res.prettyPrint();
Output: Notice login ticket
lt":"LT-12370-j4znjFQkGMXMjlT3uKJ"
Step 2. Use login ticket and perform login with username and password.
I extracted login ticket and passed to next request (continued snippet).
CookieFilter cookieFilter = new CookieFilter();
Response res1 = given().
filter(cookieFilter).
header("Content-Type","application/json").
queryParam("lt",loginticket).
queryParam("username","user1").
queryParam("password","pass1").
when().
post("/i/login?service=https://ve4al10p:443/spa").
then().
assertThat().statusCode(200).
extract().response();
res1.prettyPrint();
Output: Notice it again creates a new login ticket, that means a new session and fails give expected output.
**"lt":"LT-12369-u6osMkesdg6RQu9JPoDARL4D"**
Note: I also noticed the sessions for above requests and both are different.
Expected Output: I want to use same login ticket and maintain same sessions.

you can get the SessionID/cookie from login and pass this as SessionID to next request as header to maintain single session.
for eg :
String JsessionID = given().header(h1).body(payload).when().post(basepath).thenReturn().cookie("JSESSIONID");
given().headers(JsessionID).body(body).when().post();

How about send request with cookie?
Let's say you got access_token in cookie after login success, you can send request within the access_token in cookie:
String token = given()
.contentType(ContentType.JSON)
.body(payload)
.log()
.all()
.when()
.post(loginUrl)
.thenReturn()
.cookie("access_token");
Cookie tokenCookie = new Cookie.Builder("access_token", token)
.setSecured(true)
.setComment("some comment")
.build();
assertEquals(given()
.cookie(tokenCookie)
.when()
.get(nextRequest)
.statusCode(), 200);

Related

How to store JWT's in cookies with FastApi?

I am creating a basic Login system with FastApi, React and MongoDb.
I want to store the JWT's in cookies, but nothing worked for me and i really don't want to store them in LocalStorage...
Can someone please tell me what's wrong with my code?
#app.post("/login")
async def login(response:Response,data: OAuth2PasswordRequestForm=Depends()):
username = data.username
password = data.password
user = await query_user(username)
if not user:
raise InvalidCredentialsException
if not verify_password(password,user["password"]):
raise InvalidCredentialsException
access_token = accessToken.create(user)
refresh_token = refreshToken.create(user)
response.set_cookie(key="access_token",value=f"Bearer {access_token}", httponly=True)
response.set_cookie(key="refresh_token",value=f"Bearer {access_token}", httponly=True)
return response
This is pretty easy. In my case, once the user logs in successfully, I redirect to dashboard and then set the token in the cookies.
#app.post('/token', tags=["authenticate"])
async def login_for_access_token(response:Response, request_form: OAuth2PasswordRequestForm = Depends()):
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
token = await token_generator(request_form.username, request_form.password,
expires_delta=access_token_expires)
response = RedirectResponse(url='/api/v1/dashboard', status_code=status.HTTP_303_SEE_OTHER)
response.set_cookie(key="access_token", value=f"Bearer {token[0]}", httponly=True)
return response
My token consists of both the access_token and user_id keys, hence the token[0]. As you will notice, the 'httponly' flag is set to True. This is a security feature as there is no way to access anything about the HttpOnly cookies from "non-HTTP" APIs, e.g. JavaScript. By design, neither reading nor writing such cookies is possible. HttpOnly header flag became a standard, defined in section 5.2.6 of RFC6265, with the storage semantics described in the same document (look for "http-only-flag" throughout the RFC text). Hope this helps, good luck!

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.

Salesforce Integration With facebook messanger

I want to integrate SalesForce with Facebook Messenger. For this I've retrieved access token, app id , app secret. When I hit a HTTP request in developer console to send a message then there is an error.
In the given code it is not accepting messages as parameter throwing error but working without messages.
ref: https://developers.facebook.com/docs/messenger-platform/send-messages/?translation#sending_text
Httprequest req = new httpRequest();
req.setEndPoint('https://graph.facebook.com/v5.0/1798927698340/messages?access_token={PUT-ACCESS-TOKEN-HERE}');
String body = '{'+
'"recipient": {'+
'"id": "100042977199143"'+
'},'+
'"message": {'+
'"text": "hello, world!"' +
'}' +
'}';
req.setMethod('POST');
req.setHeader('Content-Type','application/json');
Http h = new Http();
HttpResponse res = h.send(req);
system.debug(res.getBody());
error message :
16:55:58:127 USER_DEBUG [16]|DEBUG|{"error":{"message":"Unsupported
post request. Object with ID 'me' does not exist, cannot be loaded due
to missing permissions, or does not support this operation. Please
read the Graph API documentation at
https://developers.facebook.com/docs/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AcqDT5M6mGXSOCr4mOd3kDf"}}
actual response : success = true
This problem arises sometimes when we use invalid access token or user access token instead of page access token.

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

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.