Telerik Fiddler API Test Script - set Bearer Token - fiddler

I am just now exploring the API Test capabilities in Fiddler. What a boon! I have this question:
When running a sequence of calls, the first call is to LOGIN. The result of this call contains an Access Token. On all subsequent calls, the HEADER needs to have this token in the form of:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC......
How do I script this so that the following tests have the new token assigned?

Puzzled it out:
static function BeforeTestList(arrSess: Session[]): boolean
{
// In this method, you can do any setup you need for the test,
// e.g. adding an Authorization: token OAUTH value that you
// obtained programmatically...
var sOAUTHToken = obtainToken();
if (String.IsNullOrEmpty(sOAUTHToken)) return false;
for (var i: int=0; i<arrSess.Length; i++)
{
arrSess[i].oRequest["Authorization"] = sOAUTHToken;
}
MessageBox.Show("Token Set. Running " + arrSess.Length.ToString() + " tests.", "BeforeTestList");
return true; // Test should proceed; return false to cancel
}
static function obtainToken()
{
try
{
var Content: byte[] = System.Text.Encoding.UTF8.GetBytes("{\"UserName\":\"username\",\"Password\":\"password\"}");
var oRQH: HTTPRequestHeaders = new HTTPRequestHeaders("/auth/login", ['Host: localhost:58960','Content-Length: ' + Content.length.ToString(), 'Content-Type: application/json']);
oRQH.HTTPMethod = "POST";
var oSD = new System.Collections.Specialized.StringDictionary();
var newSession = FiddlerApplication.oProxy.SendRequestAndWait(oRQH, Content, oSD, null);
if(newSession.responseCode == 200)
{
var bodyStr = newSession.GetResponseBodyAsString();
var bodyJson=Fiddler.WebFormats.JSON.JsonDecode(bodyStr);
var token = bodyJson.JSONObject["accessToken"];
//MessageBox.Show("Authorization: Bearer " + token);
return "Bearer " + token;
}
}
catch(e)
{
MessageBox.Show("send failed" + e.ToString());
}
}

Related

Xamarin Essentials Unable to exchange Okta authorization code for token

I was using OpenID and we have to switch to Xamarin.Essentials.WebAuthenticator.
I can get an authorization code from Okta using WebAuthenticator.AuthenticateAsync().
But, everything I try to then translate that code into an access token returns 400 Bad Request.
Okta's API error is "E0000021: HTTP media type not supported exception" and it goes on to say, "Bad request. Accept and/or Content-Type headers likely do not match supported values."
I have tried to follow https://developer.okta.com/blog/2020/07/31/xamarin-essentials-webauthenticator as much as possible, but we are not using the hybrid grant type like he is.
We are using only Authorization Code, which means I have to make a secondary call, and I have spent two days trying to figure out how.
private async Task LoginOktaAsync()
{
try
{
var loginUrl = new Uri(BuildAuthenticationUrl()); // that method is down below
var callbackUrl = new Uri("com.oktapreview.dev-999999:/callback"); // it's not really 999999
var authenticationResult = await Xamarin.Essentials.WebAuthenticator.AuthenticateAsync(loginUrl, callbackUrl);
string authCode;
authenticationResult.Properties.TryGetValue("code",out authCode);
// Everything works fine up to this point. I get the authorization code.
var url = $"https://dev-999999.oktapreview.com/oauth2/default/v1/token"
+"?grant_type=authorization_code"
+$"&code={authCode}&client_id={OktaConfiguration.ClientId}&code_verifier={codeVerifier}";
var request = new HttpRequestMessage(HttpMethod.Post, url);
var client = new HttpClient();
var response = await client.SendAsync(request); // this generates the 400 error.
}
catch(Exception e)
{
Debug.WriteLine($"Error: {e.Message}");
}
}
Here are the methods that produce the login url and a couple of other things:
public string BuildAuthenticationUrl()
{
var state = CreateCryptoGuid();
var nonce = CreateCryptoGuid();
CreateCodeChallenge();
var url = $"https://dev-999999.oktapreview.com/oauth2/default/v1/authorize?response_type=code"
+ "&response_mode=fragment"
+ "&scope=openid%20profile%20email"
+ "&redirect_uri=com.oktapreview.dev-999999:/callback"
+$"&client_id={OktaConfiguration.ClientId}"
+$"&state={state}"
+$"&code_challenge={codeChallenge}"
+ "&code_challenge_method=S256"
+$"&nonce={nonce}";
return url;
}
private string CreateCryptoGuid()
{
using (var generator = RandomNumberGenerator.Create())
{
var bytes = new byte[16];
generator.GetBytes(bytes);
return new Guid(bytes).ToString("N");
}
}
private string CreateCodeChallenge()
{
codeChallenge = GenerateCodeToVerify();
codeVerifier = codeChallenge;
using (var sha256 = SHA256.Create())
{
var codeChallengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeChallenge));
return Convert.ToBase64String(codeChallengeBytes);
}
}
private string GenerateCodeToVerify()
{
var str = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
Random rnd = new Random();
for (var i = 0; i < 100; i++)
{
str += possible.Substring(rnd.Next(0,possible.Length-1),1);
}
return str;
}
'''
After much online research, I discovered the issue was with how I was doing my post to get the token. This is how I made it work:
public static Dictionary<string, string> JsonDecode(string encodedString)
{
var inputs = new Dictionary<string, string>();
var json = JValue.Parse(encodedString) as JObject;
foreach (KeyValuePair<string, JToken> kv in json)
{
if (kv.Value is JValue v)
{
if (v.Type != JTokenType.String)
inputs[kv.Key] = v.ToString();
else
inputs[kv.Key] = (string)v;
}
}
return inputs;
}
private async Task<string> ExchangeAuthCodeForToken(string authCode)
{
string accessToken = string.Empty;
List<KeyValuePair<string, string>> kvdata = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", authCode),
new KeyValuePair<string, string>("redirect_uri", OktaConfiguration.Callback),
new KeyValuePair<string, string>("client_id", OktaConfiguration.ClientId),
new KeyValuePair<string, string>("code_verifier", codeVerifier)
};
var content = new FormUrlEncodedContent(kvdata);
var request = new HttpRequestMessage(HttpMethod.Post, OktaConfiguration.TokenUrl)
{Content = content, Method = HttpMethod.Post};
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.SendAsync(request);
string text = await response.Content.ReadAsStringAsync();
Dictionary<string, string> data = JsonDecode(text);
data.TryGetValue("access_token", out accessToken);
return accessToken;
}

Google API Batch Request - .NET REST Call Gives error

I am having .NET code to call the google api in batch request for getting the message details for multiple Ids. The request I am creating, when run through postman it works perfectly but when run this console app it gives me the Response Status code = 0 and Error Specified value has invalid CRLF characters.\r\nParameter name: value
Can someone please look into this and help me ... I have searched almost everything now but could not get any solution.
Here is my code --
var baseUrl = "/gmail/v1/users/" + _accountID + "/messages/";
RestClient client = null;
RestRequest request = null;
StringBuilder sbBody = null;
for (int j = 0; j < _messageId.Count; j++)
{
msgCount++;
if (msgCount == 1)
{
boundary = "testing_batch";
sbBody = new StringBuilder();
client = new RestClient("https://www.googleapis.com/batch/");
request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "multipart/mixed; boundary=\"" + boundary + "\"");
request.AddHeader("Authorization", "Bearer " + accessToken);
}
sbBody.Append(string.Format("--{0}\n", boundary));
sbBody.Append("Content-Type: application/http\n\n");
sbBody.Append(string.Format("GET {0}{1}\n\n", baseUrl, _messageId[j]));
if (msgCount == 1)
sbBody.Append(string.Format("--{0}--", boundary));
if (msgCount == 1)
{
msgCount = 0;
//request.AddBody(sbBody.ToString());
request.AddHeader("RequestBody", sbBody.ToString());
IRestResponse response = client.Execute(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//Do nothing for now
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Content);
Console.ReadLine();
break;
}
else
{
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Content);
Console.ReadLine();
break;
}
}

Rest API call for delete entity returns 403 error

Following code is aimed at deleting a row from table with given partition key and rowkey. But I get following request/response in fiddler. How can I correct the error?
Request
DELETE https://hireazurestorageacct.table.core.windows.net/mytable(PartitionKey='sample1',%20RowKey='0001')?timeout=20 HTTP/1.1
Accept: application/json;odata=nometadata
x-ms-date: Mon, 08 May 2017 17:59:14 GMT
x-ms-version: 2015-04-05
Accept-Charset: UTF-8
MaxDataServiceVersion: 3.0;NetFx
DataServiceVersion: 1.0;NetFx
If-Match: *
Content-Type: application/json
Authorization: SharedKeyLite hireazurestorageacct:3ZHX8lYBec+/9ytiNQb+JV5dpFkLAieuwB5veMkLVUU=
Host: hireazurestorageacct.table.core.windows.net
Response
HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
Content-Length: 299
Content-Type: application/json
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: a9244f7f-0002-0048-0824-c8afc5000000
Date: Mon, 08 May 2017 17:59:14 GMT
{"odata.error":{"code":"AuthenticationFailed","message":{"lang":"en-US","value":"Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:a9244f7f-0002-0048-0824-c8afc5000000\nTime:2017-05-08T17:59:14.9335100Z"}}}
Code
public static int DeleteEntity(string storageAccount, string accessKey, string tableName, string partitionkey, string rowkey)
{
string uri = $#"https://{storageAccount}.table.core.windows.net/{tableName}(PartitionKey='{partitionkey}', RowKey='{rowkey}')?timeout=20";
string resource = $#"{tableName}";
// Web request
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "DELETE";
request.Accept = "application/json;odata=nometadata";
request.Headers.Add("x-ms-date", DateTime.UtcNow.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
request.Headers.Add("x-ms-version", "2015-04-05");
request.Headers.Add("Accept-Charset", "UTF-8");
request.Headers.Add("MaxDataServiceVersion", "3.0;NetFx");
request.Headers.Add("DataServiceVersion", "1.0;NetFx");
request.Headers.Add("If-Match", "*");
request.ContentType = "application/json";
// Signature string for Shared Key Lite Authentication must be in the form
// StringToSign = Date + "\n" + CanonicalizedResource
// Date
string stringToSign = request.Headers["x-ms-date"] + "\n";
// Canonicalized Resource in the format /{0}/{1} where 0 is name of the account and 1 is resources URI path
stringToSign += "/" + storageAccount + "/" + resource;
// Hash-based Message Authentication Code (HMAC) using SHA256 hash
var hasher = new HMACSHA256(Convert.FromBase64String(accessKey));
// Authorization header
string strAuthorization = "SharedKeyLite " + storageAccount + ":" + Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign)));
// Add the Authorization header to the request
request.Headers.Add("Authorization", strAuthorization);
Thread.Sleep(1000);
// Execute the request
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (var r = new StreamReader(response.GetResponseStream()))
{
return (int)response.StatusCode;
}
}
}
catch (WebException ex)
{
// get the message from the exception response
using (var sr = new StreamReader(ex.Response.GetResponseStream()))
{
var res = sr.ReadToEnd();
// Log res if required
}
return (int)ex.Status;
}
}
Status 403 means you need to authenticate to access a resource. Any decent server will not give you anything that includes any information about the resource. So you will get the same reply, whether the resource is there or not.
According to your codes, I guess there are something wrong with your authorization token when you use the resource to generate the authorization token.
I suggest you could try below codes to delete the table entity.
Call method:
AzureTableHelper.DeleteEntity("{storageaccount}", "{accesskey}", "{tablename}", "{partitionkey}", "{rowkey}" );
Delete method:
public static int DeleteEntity(string storageAccount, string accessKey, string tableName, string partitionkey, string rowkey)
{
string host = string.Format(#"https://{0}.table.core.windows.net/", storageAccount);
string resource = string.Format(#"{0}", tableName) + string.Format("(PartitionKey='{0}',RowKey='{1}')", partitionkey, rowkey);
string uri = host + resource;
//if you want to check the etag you need firstly get the etag then delete the entity
//string jsonData = "";
//int responseCode = RequestResource(
// storageAccount,
// accessKey,
// resource,
// out jsonData);
//var jsonObject = JObject.Parse(jsonData);
//string time = jsonObject.GetValue("odata.etag").ToString();
//string time = obj.Timestamp;
// Web request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "DELETE";
request.ContentType = "application/json";
request.Accept = "application/json;odata=nometadata";
request.Headers.Add("x-ms-date", DateTime.UtcNow.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
request.Headers.Add("x-ms-version", "2015-04-05");
request.Headers.Add("If-Match", "*");
request.Headers.Add("Accept-Charset", "UTF-8");
request.Headers.Add("MaxDataServiceVersion", "3.0;NetFx");
request.Headers.Add("DataServiceVersion", "1.0;NetFx");
// Signature string for Shared Key Lite Authentication must be in the form
// StringToSign = Date + "\n" + CanonicalizedResource
// Date
string stringToSign = request.Headers["x-ms-date"] + "\n";
// Canonicalized Resource in the format /{0}/{1} where 0 is name of the account and 1 is resources URI path
stringToSign += "/" + storageAccount + "/" + resource;
// Hash-based Message Authentication Code (HMAC) using SHA256 hash
System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(accessKey));
// Authorization header
string strAuthorization = "SharedKeyLite " + storageAccount + ":" + System.Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign)));
// Add the Authorization header to the request
request.Headers.Add("Authorization", strAuthorization);
// Execute the request
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (System.IO.StreamReader r = new System.IO.StreamReader(response.GetResponseStream()))
{
string jsonResponse = r.ReadToEnd();
return (int)response.StatusCode;
}
}
}
catch (WebException ex)
{
// get the message from the exception response
using (System.IO.StreamReader sr = new System.IO.StreamReader(ex.Response.GetResponseStream()))
{
string res = sr.ReadToEnd();
// Log res if required
}
return (int)ex.Status;
}
}

(OAuthException - #200) (#200) The user hasn't authorized the application to perform this action

I'm trying out the facebook api. I'm getting this error that i'm not authorized to perform this action. I have accepted all the pop-ups that came when i run the program. Anyone got a quick soulution for this?
sing Facebook;
public void CheckAutorization()
{
string app_Id = "xxxxxxxxxxxxxxx";
string app_secret = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
string scope = "publish_stream, manage_pages";
if (Request["code"] == null)
{
Response.Redirect(string.Format(
"https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
app_Id, Request.Url.AbsoluteUri, scope));
}
else
{
Dictionary<string, string> tokens = new Dictionary<string, string>();
string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}",
app_Id, Request.Url.AbsoluteUri, scope, Request["code"].ToString(), app_secret);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string vals = reader.ReadToEnd();
foreach (string token in vals.Split('&'))
{
//meh.aspx?token1=steve&token2=jake&...
tokens.Add(token.Substring(0, token.IndexOf("=")),
token.Substring(token.IndexOf("=") + 1, token.Length - token.IndexOf("=") - 1));
}
}
string access_token = tokens["access_token"];
var client = new FacebookClient(access_token);
client.Post("/me/feed", new { message = "Is there anyone out there? :) Can i get a whoop whoop" });
}
}
}
}
Had to change the scope string scope = "publish_stream, manage_pages" to string scope = "publish_stream, publish_actions";

How to decode SessionSecurityToken

Is it possible to decode a SessionSecurityToken?
I've set up a site to work with ThinkTecture IdentityServer using MachineKeySessionSecurityTokenHandler, and everything works as expected.
But now I need to pass the token to another service, but in an Authorization HTTP header instead of a cookie.
I've tried the following:
var cookie = HttpContext.Current.Request.Cookies[FederatedAuthentication.FederationConfiguration.CookieHandler.Name];
if (cookie != null)
{
var t = MachineKey.Unprotect(Convert.FromBase64String(cookie.Value), "System.IdentityModel.Services.MachineKeyTransform");
}
but this throws a System.Security.Cryptography.CryptographicException
Found the solution.
The only (easy) way of sending the data across the wire is to convert the SessionSecurityToken to a JwtSecurityToken and use the RawData property.
Sample implementation (dependent on ThinkTecture.IdentityModel):
public JwtSecurityToken ConvertSessionToJsonWebSecurityToken(SessionSecurityToken sessionToken)
{
var h = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers[typeof(JwtSecurityToken)] as JwtSecurityTokenHandler;
if (h != null)
{
var issuer = ((ValidatingIssuerNameRegistry)h.Configuration.IssuerNameRegistry).IssuingAuthorities.First().Name;
var audience = h.Configuration.AudienceRestriction.AllowedAudienceUris.First().AbsoluteUri;
var signingKey = ((ValidatingIssuerNameRegistry)h.Configuration.IssuerNameRegistry).IssuingAuthorities.First().SymmetricKeys.First();
var securityKey = ((NamedKeyIssuerTokenResolver)h.Configuration.IssuerTokenResolver).SecurityKeys.First().Value.First();
// Create token
var t = h.CreateToken(
null,
null,
(ClaimsIdentity)sessionToken.ClaimsPrincipal.Identity,
new Lifetime(sessionToken.ValidFrom, sessionToken.ValidTo),
new SigningCredentials(
securityKey,
Algorithms.HmacSha256Signature,
Algorithms.Sha256Digest));
// Serialize token for validaiton
var s = h.WriteToken(t);
// Validate token
var validationParameters = new TokenValidationParameters()
{
AllowedAudience = audience,
ValidIssuer = issuer,
SigningToken = new BinarySecretSecurityToken(Convert.FromBase64String(signingKey))
};
h.ValidateToken(s, validationParameters);
// Return token with correct type
return h.ReadToken(s) as JwtSecurityToken;
}
return null;
}
[Test]
public void GetToken_WhenValidSessionTokenExist_ShouldReturnValidJwtToken()
{
JwtSecurityToken c;
FederatedAuthentication.SessionAuthenticationModule.TryReadJwtTokenFromCookie(container.GetInstance<ISecurityTokenOperations>(), out c)
Assert.That(!string.IsNullOrEmpty(c.RawData));
}