I have a simple mobile app in Titanium that I'm using to debug the ability to log into our user system.
At the moment, I cannot seem to see the Set-Cookie response header as it's always returned as null.
I'm currently using Titanium SDK 1.7.5 (1.8 is horribly broken).
My code is very simple, a text book example of using the HTTPClient:
var loginReq = Titanium.Network.createHTTPClient();
var url = 'https://auth.csu.edu.au/login/login.pl';
var targetURL = 'http://my.csu.edu.au'
loginButton.addEventListener('click',function(e)
{
if (username.value != '' && password.value != '')
{
loginReq.open('POST', url);
Ti.API.info('Sending HTTP Request.');
var params = {
username: username.value,
password: password.value,
url: targetURL
}
loginReq.send(params);
}
else {
alert("Username/Password are required");
}
});
loginReq.onload = function() {
var cookie = loginReq.getResponseHeader('Set-Cookie');
Ti.API.info('Response Status: ' + loginReq.status);
Ti.API.info('Response Header - Cookie: ' + cookie);
Ti.API.info('Response Header - Location: ' + loginReq.getLocation());
if (Ti.Platform.osname !== 'android')
Ti.API.info('Headers: ' + JSON.stringify(loginReq.getResponseHeaders()));
var f = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'test.html');
f.write(this.responseText);
var webview = Ti.UI.createWebView();
webview.url = f.nativePath;
var newWindow = Ti.UI.createWindow();
newWindow.add(webview);
newWindow.open({modal:true});
};
The output is as follows:
[INFO] Sending HTTP Request.
[INFO] Response Status: 200
[INFO] Response Header - Cookie: null
[INFO] Response Header - Location: https://auth.csu.edu.au/login/login.pl?redirect=true&url=http%3a%2f%2fmy%2ecsu%2eedu%2eau
[INFO] Headers: {"Connection":"Keep-Alive","Transfer-Encoding":"Identity","Keep-Alive":"timeout=5, max=99","Content-Type":"text/html","Server":"Apache/2.2.14 (Unix) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.7d mod_apreq2-20051231/2.6.0 mod_perl/2.0.4 Perl/v5.8.4","Date":"Thu, 02 Feb 2012 01:45:29 GMT"}
I'm just going around and around in circles as I can't seem to see what is exactly wrong here. What confuses me is that HTTPClient.getResponseHeaders() is not even documented (Titanium.Network.HTTPClient-object.html) - and doesn't work for Android.
I know there must be something there because the webview displays the authenticated page fine (you can't get there unless you're authorised + cookie).
How can I get a full list of the headers to make sure I'm getting all the headers I'm supposed to?
I've found the answer to my own question.
What I have in my code to return all headers is correct. Using HTTPClient.getResponseHeaders() is the correct method for iOS and HTTPClient.getAllResponseHeaders() for Android (no idea why there's two different ways - that could be a question for another day).
The reason I'm not seeing the cookie header is because of a bug in Titanium 1.7.5 (and still exists in 1.8.1). It's not forwarding on the cookie on a 302 redirect.
Jiras on the issues:
https://jira.appcelerator.org/browse/TIMOB-4537
https://jira.appcelerator.org/browse/TIMOB-1322
Related
I need to make requests to an API that accepts authentication tokens and I want to be able to use a dynamically generated token by running cmd.exe /c GenerateToken.bat instead of having to run my program and then manually paste the value in Postman every time.
I imagine something that looks like this:
How can I set the value of a HTTP header to contain the stdout output of a program or a batch file?
Short answer is, you can't. This is deliberate, both pre-request and test scripts (the only way, other than a collection runner, to make your environment dynamic) run in the postman sandbox, which has limited functionality.
More information of what is available is in the postman-sandbox Github repository page and in postman docs (scroll to the bottom to see what libraries you can import)
You do have a few options, as described in comments - postman allows sending requests and parsing the response in scripts, so you can automate this way. You do need a server to handle the requests and execute your script (simplest option is probably a small server suporting CGI - I won't detail it here as I feel it's too big of a scope for this answer. Other options are also available, such as a small PHP or Node server)
Once you do have a server, the pre-request script is very simple:
const requestOptions = {
url: `your_server_endpoint`,
method: 'GET'
}
pm.sendRequest(requestOptions, function (err, res) {
if (err) {
throw new Error(err);
} else if (res.code != 200) {
throw new Error(`Non-200 response when fetching token: ${res.code} ${res.status}`);
} else {
var token = res.text();
pm.environment.set("my_token", token);
}
});
You can then set the header as {{my_token}} in the "Headers" tab, and it will be updated once the script runs.
You can do something similar to this from Pre-request Scripts at the collection level.
This is available in postman for 9 different authorization and authentication methods.
this is a sample code taken from this article, that show how to do this in Pre-request Scripts for OAuth2
// Refresh the OAuth token if necessary
var tokenDate = new Date(2010,1,1);
var tokenTimestamp = pm.environment.get("OAuth_Timestamp");
if(tokenTimestamp){
tokenDate = Date.parse(tokenTimestamp);
}
var expiresInTime = pm.environment.get("ExpiresInTime");
if(!expiresInTime){
expiresInTime = 300000; // Set default expiration time to 5 minutes
}
if((new Date() - tokenDate) >= expiresInTime)
{
pm.sendRequest({
url: pm.variables.get("Auth_Url"),
method: 'POST',
header: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': pm.variables.get("Basic_Auth")
}
}, function (err, res) {
pm.environment.set("OAuth_Token", res.json().access_token);
pm.environment.set("OAuth_Timestamp", new Date());
// Set the ExpiresInTime variable to the time given in the response if it exists
if(res.json().expires_in){
expiresInTime = res.json().expires_in * 1000;
}
pm.environment.set("ExpiresInTime", expiresInTime);
});
}
I am trying to query my cosmos db for documents and I am having trouble generating the correct authorization header, the example in the official documentation does not show querying.
I am trying it in Postman using Javascript by POST to this URI:
POST https://MyDatabase.documents.azure.com:443/dbs/MyContainer/colls/MyDocuments/docs
With these headers:
The authorization is generated like this:
var now = new Date().toUTCString();
pm.request.headers.upsert({key: "x-ms-date", value: now })
var verb = 'POST';
var resourceType = "docs";
var resourceLink = 'dbs/MyContainer/colls/MyCollection/docs';
var text = (verb || "").toLowerCase() + "\n" +
(resourceType || "").toLowerCase() + "\n" +
(resourceLink || "") + "\n" +
now.toLowerCase() + "\n" +
"" + "\n";
//Hash and Encode by using the masterkey.
var key = CryptoJS.enc.Base64.parse("MyMasterKey");
var signature = CryptoJS.HmacSHA256(text, key).toString(CryptoJS.enc.Base64);
var authToken = encodeURIComponent("type=master&ver=1.0&sig=" + signature);
pm.request.headers.upsert({key: "Authorization", value: authToken })
Here is the error I am getting:
{
"code": "Unauthorized",
"message": "The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndocs\ndbs/MyContainer/colls/MyCollection\nwed, 27 may 2020 19:34:41 gmt\n\n'\r\nActivityId: 724657c7-0532-4c5d-a7ff-c95900ef13cf, Microsoft.Azure.Documents.Common/2.11.0"
}
I am guessing my signature is created wrong, what is the correct format?
Our docs on our Authorization Header should have what you're looking for.
hope this is helpful.
A required fix for your scenario is that you have to remove "/docs" at the end of the resourceLink value -keep it in the request URL- and also if your containter was created using a partitionKey you have to add the following header:
'x-ms-documentdb-query-enablecrosspartition': true
How do I parse a response cookie and sent back a specific value into a request header?
I'm making a request: it's sending back a token in a session cookie (token=longstrong). I need to grab that cookie, parse out token, and send back the value in a x-token: request header for following requests.
Paw is only giving me the option to send the cookie (raw).
How can I parse the response cookie to send back the value of $.token (json pseudo-code)?
A late reply, sorry!
This might help (from How do i pick specific cookies?):
Use a Custom dynamic value (right click on the field, and pick Extensions > Custom), instead, and use the following JavaScript code snippet:
function evaluate(context){
// Set here the cookies you'd like to return
var wantedCookies = ["datr", "reg_fb_ref"];
var regex = /^(\w+)\=([^;\s]+)/g;
// Request
// Uses here the current request, you can use getRequestByName("name of the request") instead
var request = context.getCurrentRequest();
// Get response cookies
var cookies = request.getLastExchange().getResponseHeaderByName("Set-Cookie").split(", ");
var filteredCookies = [];
for (var i in cookies) {
var cookie = cookies[i];
var match = regex.exec(cookie);
if (match && wantedCookies.indexOf(match[1]) >= 0) {
filteredCookies.push(match[0]);
}
}
return filteredCookies.join(",");
};
That basically parses manually the response cookies, and returns the ones you need.
This other question might help: Routes using cookie authentication from previous version of Paw no longer work on new version
I'm doing a BrowserClient POST across domains and don't see my cookies being included.
This the response I'm getting:
When I send another POST request, I don't see the cookies being included:
Going straight to the test page, I can see the cookies being included:
The Dart code I use to make a POST:
var client = new BrowserClient();
client.post(url, body: request, headers:{"Content-Type" : "application/json", "Access-Control-Allow-Credentials":"true"}).then((res) {
if (res.statusCode == 200) {
var response = JSON.decode(res.body);
callback(response);
} else {
print(res.body);
print(res.reasonPhrase);
}
}).whenComplete(() {
client.close();
});
Not sure about the Access-Control-Allow-Credentials header I'm including, with or without it, nothing changes.
Am I missing headers on the server side that needs to be set on the response or is Dartium blocking cross-domain cookies?
More details on Information Security and the reasoning behind setting cookies via the server.
Update: Enhancement request logged: https://code.google.com/p/dart/issues/detail?id=23088
Update: Enhancement implemented, one should now be able to do var client = new BrowserClient()..withCredentials=true; based on
https://github.com/dart-lang/http/commit/9d76e5e3c08e526b12d545517860c092e089a313
For cookies being sent to CORS requests, you need to set withCredentials = true. The browser client in the http package doesn't support this argument. You can use the HttpRequest from dart:html instead.
See How to use dart-protobuf for an example.
I use the UrlFetchApp to send the user and pwd (method POST). After get the cookie, and use in other request (method GET). But this new request not working, I think that this cookie not has correct use in this new request. Can anyone help me?
var opt ={
"method":"post",
"User-Agent" : "Mozilla/5.0",
"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language" : "en-US,en;q=0.5",
"payload": this.payload.toString(),
"followRedirects" : false
};
var response = UrlFetchApp.fetch("https://edas.info/addTopic.php?c=19349",opt);
var resp1=response.getContentText();
Logger.log(resp1);
response.getResponseCode();
var headers = response.getAllHeaders();
var cookies = headers['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
cookies[i] = cookies[i].split( ';' )[0];
};
opt = {
"method" : "get",
"User-Agent" : "Mozilla/5.0",
"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language" : "en-US,en;q=0.5",
"headers": {
"Cookie": cookies.join(';')
},
"followRedirects" : false
};
response = UrlFetchApp.fetch("https://edas.info/addTopic.php?c=19349", opt);
var resp1=response.getContentText();
Logger.log(resp1);
First off, thanks you for the snippet of code, this got me started with processing cookies in such script. I encountered an issue that was possibly your problem. Sometimes a Web page returns an array of cookies, and then your code works fine. Sometimes it returns a single string (instead of an array of one string). So I had to disambiguate with a test like:
if ( (cookies != null) && (cookies[0].length == 1) ) {
cookies = new Array(1);
cookies[0] = headers['Set-Cookie'];
}
I cannot give you specific help for your problem, one pointer though, as found here
Cookie handling in Google Apps Script - How to send cookies in header?
As https://stackoverflow.com/users/1435550/thierry-chevillard put it:
Be aware also that GAS uses Google IPs. It can happen that two consecutive fetch use different IPs. The server your are connecting to may be session-IP dependant.
Does your code run on the local development server and only fail once deployed to App Engine?
Or does it fail locally, as well?