Call AWS-SageMaker API in flutter - flutter

I'm trying to call a SageMaker API in flutter but the header has some issues related to Signature.
Map<String, String> signRequest(String param) {
var method = "POST";
var uri = endpoint;
var secretKey = secretKey;
var accessKey = accessKey;
var region = awsRegion;
var service = serviceType;
var host = baseUrl;
var date = DateFormat("yyyyMMdd'T'HHmmss'Z'").format(DateTime.now().toUtc());
var date2 = DateFormat("yyyyMMdd").format(DateTime.now().toUtc());
var requestBody = utf8.encode(json.encode(param.toLowerCase()));
var hashedPayloads = sha256.convert(requestBody).toString().toLowerCase();
var canonicalUri = uri;
var canonicalQuerystring = "";
var canonicalHeaders =
"content-type:application/json\nhost:$host\nx-amz-content-sha256:$hashedPayloads\nx-amz-date:$date\n";
var signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
var canonicalRequest =
"$method\n$canonicalUri\n$canonicalQuerystring\n$canonicalHeaders\n$signedHeaders\n$hashedPayloads";
var credentialScope = "$date2/$region/$service/aws4_request";
var stringToSign =
"${ApiConstants.hmacShaTypeString}\n$date\n$credentialScope\n${sha256.convert(utf8.encode(canonicalRequest))}";
var kSecret = "AWS4$secretKey";
var kDate = Hmac(sha256, utf8.encode(kSecret))
.convert(utf8.encode(date2))
.toString();
var kRegion = Hmac(sha256, utf8.encode(kDate))
.convert(utf8.encode(region))
.toString();
var kService = Hmac(sha256, utf8.encode(kRegion))
.convert(utf8.encode(service))
.toString();
var kSigning = Hmac(sha256, utf8.encode(kService))
.convert(utf8.encode("aws4_request"))
.toString();
var signature = Hmac(sha256, utf8.encode(kSigning))
.convert(utf8.encode(stringToSign))
.toString();
var authorizationHeader =
"${ApiConstants.hmacShaTypeString} Credential=$accessKey/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature";
Map<String, String> headers = {
"Content-Type": "application/json",
"X-Amz-Date": date,
"X-Amz-Content-Sha256": hashedPayloads,
"Authorization": authorizationHeader
};
return headers;
}
Status code: 403
Got this message in response:
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been"}

Related

SageMaker API Header signature issue in flutter

here is my code if anyone can help me this I would be grateful
Map<String, String> signRequest(String param) {
var method = "POST";
var uri = endpoint;
var secretKey = secretKey;
var accessKey = accessKey;
var region = awsRegion;
var service = serviceType;
var host = baseUrl;
var date = DateFormat("yyyyMMdd'T'HHmmss'Z'").format(DateTime.now().toUtc());
var date2 = DateFormat("yyyyMMdd").format(DateTime.now().toUtc());
var requestBody = utf8.encode(json.encode(param.toLowerCase()));
var hashedPayloads = sha256.convert(requestBody).toString().toLowerCase();
var canonicalUri = uri;
var canonicalQuerystring = "";
var canonicalHeaders =
"content-type:application/json\nhost:$host\nx-amz-content-sha256:$hashedPayloads\nx-amz-date:$date\n";
var signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
var canonicalRequest =
"$method\n$canonicalUri\n$canonicalQuerystring\n$canonicalHeaders\n$signedHeaders\n$hashedPayloads";
var credentialScope = "$date2/$region/$service/aws4_request";
var stringToSign =
"${ApiConstants.hmacShaTypeString}\n$date\n$credentialScope\n${sha256.convert(utf8.encode(canonicalRequest))}";
var kSecret = "AWS4$secretKey";
var kDate = Hmac(sha256, utf8.encode(kSecret))
.convert(utf8.encode(date2))
.toString();
var kRegion = Hmac(sha256, utf8.encode(kDate))
.convert(utf8.encode(region))
.toString();
var kService = Hmac(sha256, utf8.encode(kRegion))
.convert(utf8.encode(service))
.toString();
var kSigning = Hmac(sha256, utf8.encode(kService))
.convert(utf8.encode("aws4_request"))
.toString();
var signature = Hmac(sha256, utf8.encode(kSigning))
.convert(utf8.encode(stringToSign))
.toString();
var authorizationHeader =
"${ApiConstants.hmacShaTypeString} Credential=$accessKey/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature";
Map<String, String> headers = {
"Content-Type": "application/json",
"X-Amz-Date": date,
"X-Amz-Content-Sha256": hashedPayloads,
"Authorization": authorizationHeader
};
return headers;
}
Status code: 403
Got this message in response:
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been"}

Unable to retrieve API keys for a Function App using ListWebAppFunctionKeysArgs

How can I retrieve API keys for a function app in Azure using ListWebAppFunctionKeysArgs?
I have the following method:
public static Output<Dictionary<string, string>?> Get(string resourceGroupName, FunctionApp functionApp)
{
var output =
Output.Tuple(functionApp.Name, functionApp.Name)
.Apply(async tuple => {
var current = Pulumi.Azure.Core.GetClientConfig.InvokeAsync().Result;
var subscriptionId = current.SubscriptionId;
var appName = tuple.Item1;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken.Value);
var url = $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01";
var result = await httpClient.GetAsync(url);
if (!result.IsSuccessStatusCode) throw new Exception($"Error: Failed to retrive Azure function names from {appName}");
var json = await result.Content.ReadAsStringAsync();
var root = JsonConvert.DeserializeObject<JsonSupport.AzureFunctionItems.Root>(json);
var items = root.value.Select(async v => {
var data = await ListWebAppFunctionKeys.InvokeAsync(new ListWebAppFunctionKeysArgs {
Name = appName,
FunctionName = v.properties.name,
ResourceGroupName = resourceGroupName
});
return data.Properties;
});
var data = items.SelectMany(v => v.Result).ToList();
return new Dictionary<string, string>(data);
});
return output;
}
Here's the code that I'm struggling with:
var json = await result.Content.ReadAsStringAsync();
var root = JsonConvert.DeserializeObject<JsonSupport.AzureFunctionItems.Root>(json);
var items = root.value.Select(async v => {
var data = await ListWebAppFunctionKeys.InvokeAsync(new ListWebAppFunctionKeysArgs {
Name = appName,
FunctionName = v.properties.name,
ResourceGroupName = resourceGroupName
});
return data.Properties; // Property values are null
});
Here's the result:
In conclusion, how do I acquire API keys for a function app?

How to call PUT on Moodle with PutAsync?

I am trying to modernize some calls to Moodle REST APIs.
Everything is doing OK as long as I use querystring, but I can't pinpoint why using a PutAsync doesn't work in this case (tested with Postman, it works):
using (var httpClient = _httpClientFactory.CreateClient())
{
var url = "http://127.0.0.1/moodle/webservice/rest/server.php";
var urlFunction = UrlFunction.core_user_create_users.ToString();
var urlFormat = UrlFormat.json.ToString();
var requestModel = new GetCoursesRequestModel()
{
wstoken = [token],
wsfunction = urlFunction,
moodlewsrestformat = urlFormat
};
var jsonRequest = JsonConvert.SerializeObject(requestModel);
var stringContentRequest = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
var response = await httpClient.PutAsync(url, stringContentRequest);
response.EnsureSuccessStatusCode();
var courseDtos = await response.Content.ReadFromJsonAsync<List<MoodleAPIDtosCourseDto>>();
if (courseDtos is null)
throw new InputFormatterException(
$"Pb with response format.");
}
ยดยดยดยด
The error is generated when I try to read my response at await response.Content.ReadFromJsonAsync()

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;
}

Azure Storage Service throws 403 forbidden error when trying to call REST API to clear queue messages

I'm trying to clear all azure storage queue message via Queue Service REST API. I've verified that the code is correct, but it still returns a 403 forbidden error. The "StorageSharedKey" and "StorageAccountName" are correct since I'm able to connect to the azure queue using those values in the connection string for the azure queue client. The storage version I'm using is "2015-12-11".
Here is the code:
internal void ClearStorageQueueMessages(string queueName)
{
const string requestMethod = "DELETE";
string urlPath = $"{queueName}/messages";
var dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var canonicalizedHeaders = $"x-ms-date:{dateInRfc1123Format}\nx-ms-version:{StorageVersion}";
var canonicalizedResource = $"/{StorageAccountName}/{urlPath}";
var uri = new Uri($"https://{StorageAccountName}.queue.core.windows.net/{urlPath}");
var response = MakeDeleteRestCall(uri, requestMethod, dateInRfc1123Format, canonicalizedHeaders, canonicalizedResource);
}
internal RestResponse MakeDeleteRestCall(Uri uri, string requestMethod, string dateInRfc1123Format, string canonicalizedHeaders,
string canonicalizedResource)
{
var restResponse = new RestResponse();
var stringToSign = $"{requestMethod}\n\n\n\n\n\n\n\n\n\n\n\n{canonicalizedHeaders}\n{canonicalizedResource}";
var authorizationHeader = CreateAuthorizationHeader(stringToSign);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = requestMethod;
request.Headers.Add("x-ms-date", dateInRfc1123Format);
request.Headers.Add("x-ms-version", StorageVersion);
request.Headers.Add("Authorization", authorizationHeader);
//request.Accept = "application/atom+xml,application/xml";
request.Accept = "application/json";
//request.ContentType = "application/json";
using (var response = (HttpWebResponse) request.GetResponse())
{
restResponse.StatusCode = response.StatusCode;
var responseStream = response.GetResponseStream();
if (responseStream == null)
return restResponse;
using (var reader = new StreamReader(responseStream))
{
restResponse.ReturnedContent = reader.ReadToEnd();
}
}
return restResponse;
}
internal static string CreateAuthorizationHeader(string canonicalizedString)
{
string signature;
using (var hmacSha256 = new HMACSHA256(Convert.FromBase64String(StorageSharedKey)))
{
var dataToHmac = Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
var authorizationHeader = string.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", StorageSharedKey,
StorageAccountName, signature);
return authorizationHeader;
}
The problem seems to be with the header Authorization. Please check the format according to the documentation:
Authorization="[SharedKey|SharedKeyLite] :"
https://msdn.microsoft.com/en-us/library/azure/dd179428.aspx
Your function adds the shared key in plain text instead of the authorization scheme "SharedKey" or "SharedKeyLite".