I'm currently expanding one of our projects which downloads objects from an S3 bucket to support RoleAWSCredentials.
I've only connected to an S3 bucket by using BasicAWSCredentials before using an accessKey and a secretKey.
Both of these code snippets work and I'm trying to understand the functional differences to make sure that I am implementing this correctly.
// version 1
try
{
var credentials =
new BasicAWSCredentials(accessKey, secretKey);
var assumeRequest = new AssumeRoleRequest
{
RoleArn = roleArn,
DurationSeconds = 3600,
RoleSessionName = roleSessionsName,
ExternalId = externalId
};
var assumeRoleResult =
await new AmazonSecurityTokenServiceClient(credentials, RegionEndpoint.USEast1)
.AssumeRoleAsync(assumeRequest, cancellationToken);
var tempCredentials = new SessionAWSCredentials(
assumeRoleResult.Credentials.AccessKeyId,
assumeRoleResult.Credentials.SecretAccessKey,
assumeRoleResult.Credentials.SessionToken);
var s3Client = new AmazonS3Client(tempCredentials, RegionEndpoint.USEast1);
var s3listedObjects = await s3Client.ListObjectsAsync(BucketName, s3Directory , cancellationToken);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
// Version 2
try
{
var credentials =
new BasicAWSCredentials(accessKey, secretKey);
var options = new AssumeRoleAWSCredentialsOptions()
{
ExternalId = externalId,
DurationSeconds = 3600
};
var roleAwsCredentials = new AssumeRoleAWSCredentials(credentials, roleArn, roleSessionsName, options);
var amazons3 = new AmazonS3Client(roleAwsCredentials, RegionEndpoint.USEast1);
var listedObjects = await amazons3.ListObjectsAsync(BucketName, s3Directory, cancellationToken);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
The first one includes a session token, which I could see allow tracking batches of requests to different sessions but is there anything else significantly different between these two ways of using RoleAWSCredentials?
Related
I’ve used RestSharp 106 in the past but now I’m trying to get a new project up and running with v107. I did a simple test below but I can’t get it to return any data so I must be missing something that I’m not understanding. I’ve put a breakpoint at the top of the method and can follow it all the way down until it makes the async call and then the app just quits. I see the initial logging but again nothing after the async call. I would have thought I would see some logging about the list count or even the “Application END” piece. Anyone have any ideas on what I’m doing wrong? I’ve kept but commented out some of the different things I’ve tried.
Link to the documentation I’m looking at.
https://restsharp.dev/intro.html#introduction
public async void Run()
{
_log.LogInformation("Application START");
try
{
var listPPC = new List<PriorPeriodCorrection>();
listPPC = await CallApi();
}
catch (Exception ex)
{
_log.LogError("Error: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
}
_log.LogInformation("Application END");
}
public async Task<List<PriorPeriodCorrection>> CallApi()
{
var listPPC = new List<PriorPeriodCorrection>();
var apiURL = "https://example.com";
var apiEndpoint = "api/payroll/getpriorpaycorrectiondata/from/2021-12-01/to/2021-12-07";
var proxyAddress = "http://example.com:9400";
var apiUsername = "someusername";
var apiPassword = "4PsaI69#tuv";
var options = new RestClientOptions(apiURL)
{
ThrowOnAnyError = true,
Timeout = 1000,
Proxy = new WebProxy(proxyAddress)
};
var client = new RestClient(options);
client.Authenticator = new HttpBasicAuthenticator(apiUsername, apiPassword);
var request = new RestRequest(apiEndpoint);
try
{
listPPC = await client.GetAsync<List<PriorPeriodCorrection>>(request);
//var response = await client.GetAsync<PriorPeriodCorrection>(request);
//var response = await client.GetAsync<List<PriorPeriodCorrection>>(request);
//var response = await client.GetAsync(request);
//if (!string.IsNullOrWhiteSpace(response.Content))
//{
// listPPC = JsonConvert.DeserializeObject<List<PriorPeriodCorrection>>(response.Content);
//}
//else
// _log.LogInformation("Response Content is Blank or NULL.");
}
catch (Exception ex)
{
_log.LogError("Error: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
}
_log.LogInformation("Response count: {0}", listPPC.Count);
return listPPC;
}
public async Task<List<usp_TeamMeetingGetAll_Result>> TeamsMeetingReportGetAll(bool activeOnly)
{
List<usp_TeamMeetingGetAll_Result> teamMeetingGetAllResults = _db
.usp_TeamMeetingGetAll(activeOnly)
.ToList();
IEnumerable<Task<usp_TeamMeetingGetAll_Result>> taskListQuery =
from teamMeetingGetAllResult in teamMeetingGetAllResults
select TeamsMeetingGet(teamMeetingGetAllResult);
List<Task<usp_TeamMeetingGetAll_Result>> taskList = taskListQuery.ToList();
usp_TeamMeetingGetAll_Result[] results = await Task.WhenAll(taskList);
return results.OrderBy(r => r.DisplayStartDate).ToList();
}
I'm trying to figure out why line 3 (the taskList assignment) takes 7-8 seconds to execute. Line 1 calls a stored proc and puts the results (26 rows, about 15 columns) in a list and takes about 1.5 seconds. Line 2 takes less than a millisecond. Line 4 takes about 4 seconds for all async tasks to complete.
Edit: Okay, thanks to the answers below I understand that:
List<Task<usp_TeamMeetingGetAll_Result>> taskList = taskListQuery.ToList();
is causing calls to TeamsMeetingGet. I should have checked that before.
TeamsMeetingGet is making a aync call to a web API, waiting for the results, populating some properties of the usp_TeamMeetingGetAll_Result object with the results, and passing it back.
public async Task<usp_TeamMeetingGetAll_Result> TeamsMeetingGet(usp_TeamMeetingGetAll_Result teamMeetingGetAllResult)
{
//OnlineMeeting onlineMeeting = await TeamsMeetingGet(teamMeetingGetAllResult.JoinWebUrl);
HttpClient client = GraphHelper.GetAuthenticatedHttpClient();
string request =
"users/xxxxxxxxxx/onlineMeetings?$filter=JoinWebUrl%20eq%20'" + HttpUtility.UrlEncode(teamMeetingGetAllResult.JoinWebUrl) + "'";
var response = await client.GetAsync(request);
var result = await response.Content.ReadAsStringAsync();
var jresult = JObject.Parse(result);
var onlineMeetings = jresult["value"].ToObject<OnlineMeeting[]>();
if (onlineMeetings[0].Id != null)
{
teamMeetingGetAllResult.NumAttendees = onlineMeetings[0].Participants.Attendees.Count();
teamMeetingGetAllResult.Subject = onlineMeetings[0].Subject;
//More assignments
}
else
{
teamMeetingGetAllResult.NumAttendees = 0;
teamMeetingGetAllResult.Subject = "";
}
return teamMeetingGetAllResult;
}
If I have 100 rows, I'd like to call TeamsMeetingGet 100 times simultaneously, instead of synchronously. Is this how I do it?
I asked for the GetAuthenticatedHttpClient code and got back:
public class GraphHelper
{
private static string _graphClientSecret = ConfigurationManager.AppSettings["graphClientSecret"];
private static string _graphClientId = ConfigurationManager.AppSettings["graphClientId"];
private static string _graphTenantId = ConfigurationManager.AppSettings["graphTenantId"];
public static HttpClient GetAuthenticatedHttpClient()
{
IConfidentialClientApplication app;
var clientId = _graphClientId;
var tenantID = _graphTenantId;
app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(_graphClientSecret)
.WithAuthority(new Uri("https://login.microsoftonline.com/" + tenantID))
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = app.AcquireTokenForClient(scopes)
.ExecuteAsync().Result;
}
catch (MsalUiRequiredException ex)
{
// The application doesn't have sufficient permissions.
// - Did you declare enough app permissions during app creation?
// - Did the tenant admin grant permissions to the application?
throw ex;
}
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
{
// Invalid scope. The scope has to be in the form "https://resourceurl/.default"
// Mitigation: Change the scope to be as expected.
throw ex;
}
catch (Exception ex)
{
throw ex;
}
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", result.AccessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com/v1.0/");
return client;
}
}
Trying to make use of the AndroidPublisherService from Play Developer API Client.
I can list active tracks and the releases in those tracks, but when I try to upload a new build there seems to be no way of attaching the authentication already made previously to read data.
I've authenticated using var googleCredentials = GoogleCredential.FromStream(keyDataStream) .CreateWithUser(serviceUsername); where serviceUsername is the email for my service account.
private static void Execute(string packageName, string aabfile, string credfile, string serviceUsername)
{
var credentialsFilename = credfile;
if (string.IsNullOrWhiteSpace(credentialsFilename))
{
// Check env. var
credentialsFilename =
Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
EnvironmentVariableTarget.Process);
}
Console.WriteLine($"Using credentials {credfile} with package {packageName} for aab file {aabfile}");
var keyDataStream = File.OpenRead(credentialsFilename);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = edit.Execute();
Console.WriteLine($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = tracksList.Execute();
foreach (var track in tracksResponse.Tracks)
{
Console.WriteLine($"Track: {track.TrackValue}");
Console.WriteLine("Releases: ");
foreach (var rel in track.Releases)
Console.WriteLine($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
using var fileStream = File.OpenRead(aabfile);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
var uploadProgress = upload.Upload();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
Console.WriteLine($"Upload {uploadProgress.Status}");
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = "Roswell - Grenis Dev Test",
Status = "completed",
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = tracksUpdate.Execute();
Console.WriteLine($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
Console.WriteLine($"{commitResult.EditId} has been committed");
}
And as the code points out, all action objects such as tracksList.Credential = credentials; can be given the credentials generated from the service account.
BUT the actual upload action var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream"); does not expose a .Credential object, and it always fails with:
The service androidpublisher has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [401]
Errors [
Message[Login Required.] Location[Authorization - header] Reason[required] Domain[global]
]
at Google.Apis.Upload.ResumableUpload`1.InitiateSessionAsync(CancellationToken cancellationToken)
at Google.Apis.Upload.ResumableUpload.UploadAsync(CancellationToken cancellationToken)
So, how would I go about providing the actual Upload action with the given credentials here?
Managed to figure this out during the day, I was missing one call to CreateScoped() when creating the GoogleCredential object as well as a call to InitiateSession() on the upload object.
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
Once that was done I could then get a valid oauth token by calling
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
And I can now use that oauth token in the upload request:
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
The full code example for successfully uploading a new aab file to google play store internal test track thus looks something like this:
private async Task UploadGooglePlayRelease(string fileToUpload, string changeLogFile, string serviceUsername, string packageName)
{
var serviceAccountFile = ResolveServiceAccountCertificateInfoFile();
if (!serviceAccountFile.Exists)
throw new ApplicationException($"Failed to find the service account certificate file. {serviceAccountFile.FullName}");
var keyDataStream = File.OpenRead(serviceAccountFile.FullName);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = await edit.ExecuteAsync();
_logger.LogInformation($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = await tracksList.ExecuteAsync();
foreach (var track in tracksResponse.Tracks)
{
_logger.LogInformation($"Track: {track.TrackValue}");
_logger.LogInformation("Releases: ");
foreach (var rel in track.Releases)
_logger.LogInformation($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
var fileStream = File.OpenRead(fileToUpload);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
_logger.LogInformation($"Upload {uploadProgress.Status}");
var releaseNotes = await File.ReadAllTextAsync(changeLogFile);
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = $"{upload?.ResponseBody?.VersionCode}",
Status = "completed",
InAppUpdatePriority = 5,
CountryTargeting = new CountryTargeting { IncludeRestOfWorld = true },
ReleaseNotes = new List<LocalizedText>(new []{ new LocalizedText { Language = "en-US", Text = releaseNotes } }),
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = await tracksUpdate.ExecuteAsync();
_logger.LogInformation($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
commitResult.Credential = credentials;
await commitResult.ExecuteAsync();
_logger.LogInformation($"{commitResult.EditId} has been committed");
}
Plaid.Net is fully functional and can it be used in production code?
I am trying to create a link token like below
var plaid = new PlaidClient(Acklann.Plaid.Environment.Development);
string[] products = new string[] { "transactions" };
string[] countryCodes = new string[] { "US" };
var user = new UserInfo();
user.ClientUserId = "123bs6a4";
var createLinkTokenRequest = new CreateLinkTokenRequest
{
ClientId = "*****************",
Secret = "****************",
Products = products,
CountryCodes = countryCodes,
Language = "en",
ClientName = "My client",
User=user
};
try
{
var result = getToken(createLinkTokenRequest);
}
catch(Exception e)
{
Console.WriteLine(e);
Console.ReadKey();
}
public static async Task<CreateLinkTokenResponse> getToken(CreateLinkTokenRequest createLinkTokenRequest)
{
var plaid = new PlaidClient(Acklann.Plaid.Environment.Development);
try
{
var res= await plaid.CreateLinkToken(createLinkTokenRequest);
Console.WriteLine(res.LinkToken);
return res;
}
catch(Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.WriteLine("Abc");
Console.ReadKey();
}
While debugging when I reach
await plaid.CreateLinkToken(createLinkTokenRequest);
the execution is stopped without an execption
is this the right way of creating link token or any other way?
(using .Net core 2.1, Acklann.Plaid Nuget)
Try to change the environment from development to sandbox. Maybe you are using the sandbox key and passing environment as development.
I want to create push notifications to my Alexa Devide. Due the push notification program is closed I am trying to create reminders. The final idea is to create an Azure Function with this code and being called when a TFS Build faild.
I'm using Alexa.NET and Alexa.NET.Reminders from a console application, already have and Alexa Skill with all the permissions granted, in the Alexa portal and in the mobile app.
Everything seems to work nice until I try to read the reminders in my account, when get an exception "Invalid Bearer Token"
this is the code:
[Fact]
public async Task SendNotificationTest()
{
var clientId = "xxxx";
var clientSecret = "yyyy";
var alexaClient = clientId;
var alexaSecret = clientSecret;
var accessToken = new Alexa.NET.AccessTokenClient(Alexa.NET.AccessTokenClient.ApiDomainBaseAddress);
var token = await accessToken.Send(alexaClient, alexaSecret);
var reminder = new Reminder
{
RequestTime = DateTime.UtcNow,
Trigger = new RelativeTrigger(12 * 60 * 60),
AlertInformation = new AlertInformation(new[] { new SpokenContent("test", "en-GB") }),
PushNotification = PushNotification.Disabled
};
var total = JsonConvert.SerializeObject(reminder);
var client = new RemindersClient("https://api.eu.amazonalexa.com", token.Token);
var alertList = await client.Get();
foreach (var alertInformation in alertList.Alerts)
{
Console.WriteLine(alertInformation.ToString());
}
try
{
var response = await client.Create(reminder);
}
catch (Exception ex)
{
var x = ex.Message;
}
}
Are there any examples to get the access token?
Am I missing a step in the process?
Thanks in advance.
N.B. The reminders client requires that you have a skill with reminders persmission enabled, and the user must have given your skill reminders permission (even if its your development account)
Creating a reminder
using Alexa.NET.Response
using Alexa.NET.Reminders
....
var reminder = new Reminder
{
RequestTime = DateTime.UtcNow,
Trigger = new RelativeTrigger(12 * 60 * 60),
AlertInformation = new AlertInformation(new[] { new SpokenContent("it's a test", "en-GB") }),
PushNotification = PushNotification.Disabled
};
var client = new RemindersClient(skillRequest);
var alertDetail = await client.Create(reminder);
Console.WriteLine(alertDetail.AlertToken);
Retrieving Current Reminders
// Single reminders can be retrieved with client.Get(alertToken)
var alertList = await client.Get();
foreach(var alertInformation in alertList.Alerts)
{
//Your logic here
}
Deleting a Reminder
await client.Delete(alertToken);