AWS List user folder for S3 - c#

Creating a C# application to view folders and files that are stored in AWS S3 for clients that sign up to my site.
Currently I can create a IAM user and assign it permission to a specific folder. But ran into issues when I am trying to view the folder and its contents. I can view the folder if I use the AWS access key and secret key but was wondering if there is a user level credential that I can use to retrieve the folders the user has been given permission to?
This is what I have got so far.
Policy pl = GeneratePolicy(bucketName, foldername);
Credentials creds = GetFederatedCredentials(pl, username);
var sessionCredentials = new SessionAWSCredentials(creds.AccessKeyId, creds.SecretAccessKey, creds.SessionToken);
using (var client = new AmazonS3Client(sessionCredentials, Amazon.RegionEndpoint.USEast1))
{
var response = client.ListObjects(request);
foreach (var subFolder in response.CommonPrefixes)
{
/* list the sub-folders */
Console.WriteLine(subFolder);
}
foreach (var file in response.S3Objects)
{
/* list the files */
}
}
But getting an error on client.ListObjects(request) - access denied error
Here is the GeneratePolicy code
public static Policy GeneratePolicy(string bucket, string username)
{
var statement = new Statement(Statement.StatementEffect.Allow);
// Allow access to the sub folder represented by the username in the bucket
statement.Resources.Add(ResourceFactory.NewS3ObjectResource(bucket, username + "/*"));
// Allow Get and Put object requests.
statement.Actions = new List<ActionIdentifier>() { S3ActionIdentifiers.GetObject, S3ActionIdentifiers.PutObject };
// Lock the requests coming from the client machine.
//statement.Conditions.Add(ConditionFactory.NewIpAddressCondition(ipAddress));
var policy = new Policy();
policy.Statements.Add(statement);
return policy;
}
Here is the GetFederatedCredentials code
public static Credentials GetFederatedCredentials(Policy policy, string username)
{
var request = new GetFederationTokenRequest()
{
Name = username,
Policy = policy.ToJson()
};
var stsClient = new AmazonSecurityTokenServiceClient(AWS_ACCESS_KEY, AWS_SECRET_KEY, Amazon.RegionEndpoint.USEast1);
var response = stsClient.GetFederationToken(request);
return response.GetFederationTokenResult.Credentials;
}
Any help would be greatly appreciated. Thanks in advance

You should add "ListBucket" to the statement.Actions

Related

C# app "upload file to google drive" request returning as null

I have a C# desktop app which allows the user to backup its to google drive via the google drive api V3.
I have the following method in a class which is used to load the backups
static string[] Scopes = { DriveService.Scope.DriveFile };
static string ApplicationName = "MyApp";
private static string CreateFile(string pFilePath, string parentFolderId, DriveService service)
{
var fileMetaData = new Google.Apis.Drive.v3.Data.File();
fileMetaData.Name = Path.GetFileName(pFilePath);
fileMetaData.MimeType = "application/vnd.google-apps.file";
fileMetaData.Parents = new List<string> { parentFolderId };
FilesResource.CreateMediaUpload request;
using(var stream = new FileStream(pFilePath, FileMode.Open))
{
request = service.Files.Create(fileMetaData, stream, "application/vnd.google-apps.file");
request.Fields = "id";
request.Upload();
}
var file = request.ResponseBody;
return file.Id;
}
Upon reaching request.Upload(), the request doesn't seem to have any issues, but later on after the file declaration, file turns out to be null, so no response body and thus no id either.
Is there something wrong with my request? I tried to see if I could catch an Exception in upload, which the method description claims would be of type IUploadProgress.Exception, but such an interface doesn't actually have an Exception property.
I've already authenticated and I managed to create a folder (which is the ID passed by argument parentFolderId, confirmed to not be null), so I am able to communicate with drive, just that this particular upload isn't working.
This is the code i use How to upload a file to Google Drive with C# .net I use the async method personally
string uploadedFileId;
// Create a new file on Google Drive
await using (var fsSource = new FileStream(UploadFileName, FileMode.Open, FileAccess.Read))
{
// Create a new file, with metadata and stream.
var request = service.Files.Create(fileMetadata, fsSource, "text/plain");
request.Fields = "*";
var results = await request.UploadAsync(CancellationToken.None);
if (results.Status == UploadStatus.Failed)
{
Console.WriteLine($"Error uploading file: {results.Exception.Message}");
}
// the file id of the new file we created
uploadedFileId = request.ResponseBody?.Id;
}
As for your code i think you need execute on the end
request.Upload().Execute;

Using explicit credentials in a C# dialogflow application

I'm creating a C# application that uses DialogFlow's detectIntent. I need help passing the Google Cloud credentials explicitly.
It works with the GOOGLE_APPLICATION_CREDENTIALS environment variable. However I want to pass the credentials explicitly. I need a C# version of the solution provided here.
I'm using the following quick-start provided with the documentation:
public static void DetectIntentFromTexts(string projectId,
string sessionId,
string[] texts,
string languageCode = "en-US")
{
var client = df.SessionsClient.Create();
foreach (var text in texts)
{
var response = client.DetectIntent(
session: new df.SessionName(projectId, sessionId),
queryInput: new df.QueryInput()
{
Text = new df.TextInput()
{
Text = text,
LanguageCode = languageCode
}
}
);
var queryResult = response.QueryResult;
Console.WriteLine($"Query text: {queryResult.QueryText}");
if (queryResult.Intent != null)
{
Console.WriteLine($"Intent detected: {queryResult.Intent.DisplayName}");
}
Console.WriteLine($"Intent confidence: {queryResult.IntentDetectionConfidence}");
Console.WriteLine($"Fulfillment text: {queryResult.FulfillmentText}");
Console.WriteLine();
}
}
Currently you need to create a gRPC channel directly, and pass that into the client:
GoogleCredential credential = GoogleCredential.FromFile("...");
ChannelCredentials channelCredentials = credential.ToChannelCredentials();
Channel channel = new Channel(SessionsClient.DefaultEndpoint, channelCredentials);
var client = df.SessionsClient.Create(channel);
Very soon, this will be a lot easier via a builder pattern:
var client = new SessionsClientBuilder
{
CredentialsPath = "path to file",
}.Build();
... or various other ways of specify the credential. I'm hoping that'll be out in the next couple of weeks.

Access denied when downloading file from Sharepoint CSOM

I am trying to download a file from a client Sharepoint site. I am using sharepoint CSOM.
My code is as follows:
using Microsoft.SharePoint.Client;
var username = "username";
var password = "pass";
var url = "https://myclient.sharepoint.com/";
var fileurl = "https://myclient.sharepoint.com/teams/folder1/folder%20x/somefile.docx";
using (ClientContext context = new ClientContext(url))
{
SecureString passWord = new SecureString();
foreach (char c in password.ToCharArray()) passWord.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials(username, passWord);
Uri filename = new Uri(fileurl);
string server = filename.AbsoluteUri.Replace(filename.AbsolutePath, "");
string serverrelative = filename.AbsolutePath;
Microsoft.SharePoint.Client.File file = context.Web.GetFileByServerRelativeUrl(serverrelative);
context.Load(file);
ClientResult<Stream> streamResult = file.OpenBinaryStream();
context.ExecuteQuery();
var file2 = streamResult.Value;
}
The problem is that I get access denied, yet when I log in with the same credentials, I can download the file successfully.
Is there a separate permission in Sharepoint for downloading file from API instead of UI?
Could the space in the folder name be the problem?
UPDATE
Verified this does not have anything to do with spaces in folder or filename.
In case if SharePoint site uses multiple authentication providers using a set of Windows credentials (also relevant for SharePoint Online), the additional header must be included in a request: X-FORMS_BASED_AUTH_ACCEPTED with a value of f
For ClientContext class the header could be included like this:
ctx.ExecutingWebRequest += (sender, e) =>
{
e.WebRequestExecutor.WebRequest.Headers["X-FORMS_BASED_AUTH_ACCEPTED"] = "f";
};
Example
var file = ctx.Web.GetFileByUrl(fileAbsUrl);
ctx.Load(file);
var streamResult = file.OpenBinaryStream();
ctx.ExecuteQuery();
//save into file
using (var fileStream = System.IO.File.Create(#"C:\path\filename.docx"))
{
streamResult.Value.Seek(0, SeekOrigin.Begin);
streamResult.Value.CopyTo(fileStream);
}
Note: instead of converting to relative url, GetFileByUrl
method is used which accepts absolute url
Problem was that I was not connecting to the right url (new ClientContext(url))
I was connecting to: https://myclient.sharepoint.com/
I should have been connecting to: https://myclient.sharepoint.com/teams/folder1/

Creating folder using Google Drive API gives invalid_grant but can create actual file with same connection

I can setup a Google user content connection with Google API and can get folders and even upload/create files to folders. But the same connection used to create a new regular folder anywhere gives the error invalid_grant with no further information. I am passing in a valid folderId to set as parent. I have tried different scopes and a long shot of syncing my clock like I have seen on other solutions. I can't seem to figure out the issue. Anyone else have seen this?
Here is code that works to upload a file to a folder:
public async Task<string> Upload(string localFilePath, string folderId, string fileName, string refreshToken, string userId)
{
var file = new File();
file.MimeType = GetMimeType(localFilePath);
file.Name = fileName;
file.Parents = new List<string> { folderId };
var driveService = await GetDriveService(refreshToken, userId);
// File's content.
var byteArray = System.IO.File.ReadAllBytes(localFilePath);
var stream = new System.IO.MemoryStream(byteArray);
var request = driveService.Files.Create(file, stream, file.MimeType);
await request.UploadAsync();
return request.ResponseBody.Id;
}
Here is what I've been trying in creating a folder:
public async Task<string> CreateFolder(string folderId, string folderName, string refreshToken, string userId)
{
var newFolderId = string.Empty;
var driveService = await GetDriveService(refreshToken, userId);
FilesResource.ListRequest list = driveService.Files.List();
var file = new File();
file.MimeType = "application/vnd.google-apps.folder";
file.Name = folderName;
file.Parents = new List<string> { folderId };
var request = driveService.Files.Create(file);
request.Fields = "Id";
var newFolder = await request.ExecuteAsync();
return newFolder.Id;
}
And, here is the method in defining driveService:
private async Task<DriveService> GetDriveService(string refreshToken, string userId)
{
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecrets: new ClientSecrets { ClientId = "xyz.apps.googleusercontent.com", ClientSecret = "xyz" },
scopes: new string[] { DriveService.Scope.Drive, DriveService.Scope.DriveFile },
dataStore: new MemoryDataStore(userId, refreshToken),
user: userId,
taskCancellationToken: CancellationToken.None);
var driveService = new DriveService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "XYZ"
});
return driveService;
}
As mentioned in creating a folder,
In the Drive API, a folder is essentially a file — one identified by the special folder MIME type application/vnd.google-apps.folder. You can create a new folder by inserting a file with this MIME type and a folder title. Do not include an extension when setting a folder title.
Please try using the given code:
File fileMetadata = new File();
fileMetadata.setName("Invoices");
fileMetadata.setMimeType("application/vnd.google-apps.folder");
File file = driveService.files().create(fileMetadata)
.setFields("id")
.execute();
System.out.println("Folder ID: " + file.getId());
I apologize, I am a victim of a copy/paste or fat finger error that I just did not notice unfortunately until now. I am managing multiple cloud connections in this app for similar purposes, and at the beginning of the call in this case to create folder I either copy/pasted or fat fingered an enum value that was improperly requesting to get the saved refreshtoken from a different cloud provider ala one drive or dropbox. Once switched to pull the saved google refreshtoken, it works. Well, at least there is a working example of create folder and upload file above :-) Btw, the line request.Fields = "Id"; needs to be request.Fields = "id"; where id needs to be lower case...otherwise a different error pops up saying the field is invalid. Thanks.

How to fetch change from Git using LibGit2Sharp?

The code below clone a Git url to a test directory.
var url = #"http://abc-555.com/team/project-555.git";
var path = #"E:\temp_555";
var credential = new Credentials() { Username = "a8888", Password="88888888"};
var clonePath = Repository.Clone(url, path, credentials: credential);
using (var repo = new Repository(clonePath))
{
foreach (var branch in repo.Branches)
{
Console.WriteLine(branch.Name);
}
// somebody creates a new branch here, so I want to fetch it.
repo.Fetch("origin");
foreach (var branch in repo.Branches)
{
Console.WriteLine(branch.Name);
}
}
I want to fetch a new branch before merging it to local Git. Anyway, it throws An error was raised by libgit2. Category = Net (Error). Request failed with status code: 401 exception.
How to fix this?
You can specifiy the credentials to be used through a FetchOptions instance as the last parameter of the Fetch call.
repo.Fetch("origin", new FetchOptions { Credentials = credential});

Categories