How do I change a GET to a POST using Fiddler scripting? - fiddler

I have dug around and cannot find any way to get a GET into a POST using Fiddler. Given all the rest of what it does I expect there is some way to do it.
I have written enough Fiddler script to find the right URL and start manipulating it, but not that last bit. The reason I need to do this is that a web client I am working with needs to change the way it sends credentials, but another group handles it and it will take some time for them to get to it. Here is the code that I have so far:
if (oSession.fullUrl.Contains("j_spring_security_check") > -1)
{
var newUrl:String;
newUrl = oSession.fullUrl;
if (newUrl.Contains("j_username"))
newUrl = newUrl.Replace("j_username", "username");
if (newUrl.Contains("j_password"))
newUrl = newUrl.Replace("j_password", "password");
FiddlerObject.alert(newUrl);
// ### I need to change it from a GET to POST here ###
FiddlerObject.alert(newUrl);
}

An admin over on a Fiddler message board gave me enough information to work this out.
Here is the working solution:
if (oSession.fullUrl.Contains("j_spring_security_check") &&
oSession.fullUrl.Contains("j_username") &&
oSession.HTTPMethodIs("GET"))
{
var newUrl:String;
newUrl = oSession.fullUrl;
if (newUrl.Contains("j_username"))
newUrl = newUrl.Replace("j_username", "username");
if (newUrl.Contains("j_password"))
newUrl = newUrl.Replace("j_password", "password");
FiddlerObject.alert(newUrl);
oSession.oFlags["ui-backcolor"] = "lightgreen"; // jbp for debug use
oSession.oRequest.headers.HTTPMethod = "POST";
oSession.oRequest["Content-Type"] = "application/x-www-form/urlencoded";
oSession.utilSetRequestBody("");
oSession.fullUrl = newUrl;
FiddlerObject.alert(oSession.fullUrl.ToString());
}

Related

Fiddler: Cannot set the Response Code in

We are using the Fiddler customRules.js script to handle our API testing (external APIs from other companies when they do not have Test Servers for us) where we send a response file back to the requestor if one is present, otherwise we build the response. This is working fine, but I cannot set the HTTP Status code.
When we generate the response, in some cases we want to be able to specify the HTTP Status to what the external API might send.
static function OnBeforeResponse(oSession: Session) {
if (m_Hide304s && oSession.responseCode == 304) {
oSession["ui-hide"] = "true";
}
// Set Header values for later
var HeaderContentType = 'text/xml;charset=utf-8';
var HeaderServer = 'Apache-Coyote/1.1';
var HttpStatus = 200;
... // This is the removed code that determines text or file to return
// At the end of our process to determine to send a file or error we try to send an error value in this case. For simplicity, I am just hard assigning it without using a variable as we normally would.
oSession.responseCode = 500;
oSession.oResponse.headers.HTTPResponseCode = 500;
oSession.oResponse.headers.HTTPResponseStatus = "500 SERVER ERROR";
oSession.ResponseHeaders.SetStatus(500, 'Server Error'); // This also does not work
// However this does work to add the file contents into the response when the file exists.
var ResponseFile = new ActiveXObject("Scripting.FileSystemObject");
if (ResponseFile.FileExists(ReturnFileName)) {
oSession["x-replywithfile"] = ReturnFileName;
// Error message returned as the ReturnBody was not populated and Response File not found
} else {
oSession.utilSetResponseBody(ErrorMessage);
}
return;
}
Finally tracked it down. The problem is that I am often returning a file when returning an error using the oSession["x-replywithfile"]. However, this always makes the status an 200 OK, even if I try to change the status after the oSession["x-replywithfile"] setting.
oSession["x-replywithfile"] = ReturnFileName;
oSession.responseCode = 500;
This will still always return a 200 OK.
Changing to the following will work.
var FileContents = ReadFile(ReturnFileName);
oSession.utilSetResponseBody(FileContents);
oSession.responseCode = 500;

How to call SSRS Rest-Api V1.0 with custom security implemented (NOT SOAP)

I have implemented the custom security on my reporting services 2016 and it displays the login page once the URL for reporting services is typed on browser URL bar (either reports or reportserver)
I am using the following code to pass the Credentials
when i use the code WITHOUT my security extension it works and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"NTLM", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
when i use the code WITH the security extension it doesnt work and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"Basic", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
and i get an Exception saying "The response to this POST request did not contain a 'location' header. That is not supported by this client." when i actually use this credentials
Is "basic" the wrong option ?
Have anyone done this ?
Update 1
Well it turns out that my SSRS is expecting an Authorisation cookie
which i am unable to pass (according to fiddler, there is no cookie)
HttpWebRequest request;
request = (HttpWebRequest)HttpWebRequest.Create("http://mylocalcomputerwithRS/Reports_SQL2016/api/v1.0");
CookieContainer cookieJar = new CookieContainer();
request.CookieContainer = cookieJar;
Cookie authCookie = new Cookie("sqlAuthCookie", "username:password");
authCookie.Domain = ".mydomain.mylocalcomputerwithRS";
if (authCookie != null)
request.CookieContainer.Add(authCookie);
request.Timeout = -1;
HttpWebResponse myHttpWebResponse = (HttpWebResponse)request.GetResponse();
That's how I got it (SSRS 2017; api v2.0). I took the value for the "body" from Fiddler:
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler);
Assert.AreEqual(0, handler.CookieContainer.Count);
// Create a login form
var body = new Dictionary<string, string>()
{
{"__VIEWSTATE", "9cZYKBmLKR3EbLhJvaf1JI7LZ4cc0244Hpcpzt/2MsDy+ccwNaw9hswvzwepb4InPxvrgR0FJ/TpZWbLZGNEIuD/dmmqy0qXNm5/6VMn9eV+SBbdAhSupsEhmbuTTrg7sjtRig==" },
{"__VIEWSTATEGENERATOR", "480DEEB3"},
{ "__EVENTVALIDATION", "IS0IRlkvSTMCa7SfuB/lrh9f5TpFSB2wpqBZGzpoT/aKGsI5zSjooNO9QvxIh+QIvcbPFDOqTD7R0VDOH8CWkX4T4Fs29e6IL92qPik3euu5QpidxJB14t/WSqBywIMEWXy6lfVTsTWAkkMJRX8DX7OwIhSWZAEbWZUyJRSpXZK5k74jl4x85OZJ19hyfE9qwatskQ=="},
{"txtUserName", "User"},
{"txtPassword", "1"},
{"btnLogin","Войти"}
};
var content = new FormUrlEncodedContent(body);
// POST to login form
var response = await httpClient.PostAsync("http://127.0.0.1:777/ReportServer/Logon.aspx", content);
// Check the cookies created by server
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var cookies = handler.CookieContainer.GetCookies(new Uri("http://127.0.0.1:777/ReportServer"));
Assert.AreEqual("sqlAuthCookie", cookies[0].Name);
// Make new request to secured resource
var myresponse = await httpClient.GetAsync("http://127.0.0.1:777/Reports/api/v2.0/Folders");
var stringContent = await myresponse.Content.ReadAsStringAsync();
Console.Write(stringContent);
As an alternative you can customize SSRS Custom Security Sample quite a bit.
I forked Microsoft's Custom Security Sample to do just what you are describing (needed the functionality at a client long ago and reimplemented as a shareable project on GitHub).
https://github.com/sonrai-LLC/ExtRSAuth
I created a YouTube walkthrough as well to show how one can extend and debug SSRS security with this ExtRSAuth SSRS security assembly https://www.youtube.com/watch?v=tnsWChwW7lA
TL; DR; just bypass the Microsoft example auth check in Login.aspx.cs and put your auth in Page_Load() or Page_Init() event of Login.aspx.cs- wherever you want to perform some custom logging check- and then immediately redirect auth'd user to their requested URI.

Sharepoint authentication without using sharepoint development environment or service references?

I am trying to access a local SharePoint site using a .net program and am having difficulties.
I don't want to use the SharePoint development environment (may have many developers work on this, and that is just one more thing to install).
I would also like to make this configurable so that I can change the site and list name without recompiling. I don't think I can do that with the Service References. If I can, how?
I also don't want the user to enter sharepoint validation information, I am ok with storing sharepoint login information in a .config file.
I believe I could do this with REST, but can't figure out how to create an AccessToken without using the Sharepoint development environment.
Any help would be appreciated.
The main problem I was having was not understanding that you could put other types of credentials in the request.Credentials property. Here is the code I created:
public bool CopyFileToSharePoint(string fileName, Stream fileStream)
{
var data = new byte[fileStream.Length];
fileStream.Read(data, 0, (int) fileStream.Length);
fileStream.Close();
var sharePointPath =
SharePointWebSiteUrl + "/_api/web/lists/getByTitle('" + SharePointListName + "')" +
"/RootFolder/Files/add(url='" + fileName + "',overwrite='true')";
var request = (HttpWebRequest) WebRequest.Create(sharePointPath);
request.Credentials = new NetworkCredential(SharePointUserName, SharePointPassword, SharePointLoginDomain);
request.Method = "POST";
request.Accept = "application/atom+xml";
request.Headers["X-RequestDigest"] = GetFormDigest(SharePointWebSiteUrl);
request.ContentType = "application/txt";
request.ContentLength = data.Length;
request.GetRequestStream().Write(data, 0, data.Length);
var response = (HttpWebResponse) request.GetResponse();
return response.StatusCode == HttpStatusCode.OK;
}
I'm sure it's not perfect, but it works.

How do I get the redirect url?

I want to get a redirect url from a url.
Url:
https://api.soundcloud.com/tracks/151935719/stream?client_id=
redirect url looks something like this:
https://ec-media.soundcloud.com/0fdDn45vb5t4.128.mp3?f10880d39085a94a0418a7ef69b03d522cd6dfee9399eeb9a522019d6afabf3e3c10bce51c30cbe03f40dfc788e191ee959a960c826c0a5de46a851702613b05f3906a2971&AWSAccessKeyId=AKIAJNIGGLK7XA7YZSNQ&Expires=1401521245&Signature=B3P8qLw1t%2BQ2oYQUEfpep9%2FULXg%3D
How do I get the redirect url so I can stream from this link?
I am using C# WPF and I am a newbie.
Thanks!!
It should be automatic with HttpWebRequest.AllowAutoRedirect:
HttpWebRequest request = HttpWebRequest.CreateHttp(yourURI);
request.AllowAutoRedirect = true;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Your code
}
However, the default value for AllowAutoRedirect is true, so, in general, you shouldn't even need to set it. Redirection is automatically handled:
HttpWebRequest request = HttpWebRequest.CreateHttp(yourURI);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Your code
}

Must/can I install MS ASP.NET Web API Client Libraries in order to post data to my Web API server?

Do I need to install ASP.NET Web API Client Libraries (as this article indicates) in order to post data to a Web API server? If so, can I do so in Visual Studio 2008 from a Windows CE project?
The reasons I wonder are:
0) The client is a Windows CE project, for which I'm using Visual Studio 2008, and I don't know if ASP.NET Web API Client Libraries are available for that version; I know I don't have the NuGet Package Manager in that environment.
1) I am successfully querying data from my RESTful Web API methods without installing ASP.NET Web API Client Libraries, using code like this:
while (true)
{
deptList.departments.Clear();
string uri = String.Format("http://platypi:28642/api/Duckbills/{0}/{1}", lastIdFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest) WebRequest.Create(uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string jsonizedDuckbills = reader.ReadToEnd();
List<Duckbill> duckbills = JsonConvert.DeserializeObject<List<Duckbill>>(jsonizedDuckbills);
if (duckbills.Count <= 0) break;
foreach (Duckbill duckbill in duckbills)
{
duckbillList.duckbills.Add(duckbill);
lastIdFetched = duckbill.Id;
}
} // if ((webResponse.StatusCode == HttpStatusCode.OK)
} // using HttpWebResponse
int recordsAdded = LocalDBUtils.BulkInsertDuckbills(duckbillList.duckbills);
totalRecordsAdded += recordsAdded;
} // while (true);
I'm stuck on posting, though, and the cleanest example I've seen so far for doing so is at that link already shown above.
I got an answer to my question on how to post here, but that hasn't made me smart enough yet to actually accomplish it. It's a step in the right direction, perhaps, although I reckon, based on how my client query code looks, that the client posting code would be of similar "style" (like the previously referenced article here, and unlike the likewise previously referenced answer here).
UPDATE
If I'm already providing the data in the uri string itself, as I am, like this:
string uri = String.Format("http://shannon2:28642/api/Departments/{0}/{1}", onAccountOfWally, moniker);
...why would I need to also specify it in postData? Or could I set postData (if that's just a necessary step to get the length) to those values...something like:
postData = String.Format("{0}, {1}", onAccountOfWally, moniker);
?
To talk to ASP.NET Web API, you do not necessarily need the client library, although it makes the life easier. After all, one of the benefits of HTTP services is the platform reach. Literally you can use any library that gives you HTTP capabilities. So, using WebRequest, you can do something like this. I'm using JSON in the payload. You can use XML and application/www-form-urlencoded as well. Just that you need to format the request body accordingly. Also, for complex objects, you will be better off using JSON.NET unlike formatting the JSON manually.
var request = System.Net.WebRequest.Create("http://localhost:12345/api/values");
request.Method = "POST";
string postData = "{\"firstName\":\"Steven\"," + "\"lastName\":\"Waugh\"}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/json";
request.ContentLength = byteArray.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(byteArray, 0, byteArray.Length);
}
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var reader = new System.IO.StreamReader(responseStream))
{
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
}
}
}
EDIT
If you are specifying data in URI, you do not need to specify the same in the request body. To let web API bind the parameters for you from URI, you will need to specify the route accordingly so that the placeholders are set for onAccountOfWally and moniker. Then you will need to use a simple type like string as action method parameters for web API to bind. By default, simple types are bound from URI path and query string and complex types from request body.