Nuget.Core Download all Nuget-Packages Authentication failing - c#

I want to download all nuget packages from a private nuget feed, but my authentication is failing.
public void DownloadPackages(string repositoryPath, string directoryPath)
{
var repo = PackageRepositoryFactory.Default
.CreateRepository(repositoryPath);
var allPackages = repo.GetPackages();
foreach (var package in allPackages)
{
var fileName = Path.ChangeExtension(Path.Combine(directoryPath, package.GetFullName()), ".nupkg");
Console.WriteLine($"Downloading {package.GetFullName()}");
try
{
using (var stream = package.GetStream())
{
using (var fileStream = File.Create(fileName))
{
stream.CopyTo(fileStream);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error while downloading {package.GetFullName()}: {ex.Message}");
}
}
}
public void InitializeCredentials(string url, string userName, string password)
{
var credentials = new NetworkCredential(userName, password);
CredentialStore.Instance.Add(new Uri(url), credentials);
}
I initialize my Credentials like this with InitializeCredentials.
But it still gives me Error 401 from the server.
I saw that visual studio generated an ApiKey for my private nuget-feed.
How can I place my ApiKey into my code - I see no possibility at var repo = PackageRepositoryFactory.Default .CreateRepository(repositoryPath); for example.
So I think my problem is the missing ApiKey, but maybe I am using the wrong authentication InitializeCredentials ?
EDIT:
So I am sure now - that it can't be the ApiKey - but what am I missing?
EDIT:
I am calling my methods like this:
var helper = new PackageHelper();
helper.InitializeCredentials("User","Password");
helper.DownloadPackages("NuGetUrl", "MyLocalFolder");

Related

DocuSign foldersapi authentication problem in C# wrong username or password

I have downloaded the console application from DocuSign website (JWT grant remote signing). It is working well but when I try to use FoldersApi it is throwing a "USER_AUTHENTICATION_FAILED One or both of Username and Password are invalid. Invalid access token" error. Is it somehow related to apiClient? How was it able to send email if the username and password is wrong?
namespace DocuSign.CodeExamples.JWT_Console
{
class Program
{
static readonly string DevCenterPage = "https://developers.docusign.com/platform/auth/consent";
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.White;
OAuthToken accessToken = null;
try
{
accessToken = JWTAuth.AuthenticateWithJWT("ESignature", ConfigurationManager.AppSettings["ClientId"], ConfigurationManager.AppSettings["ImpersonatedUserId"],
ConfigurationManager.AppSettings["AuthServer"], ConfigurationManager.AppSettings["PrivateKeyFile"]);
}
catch (ApiException apiExp)
{
//Removed this section because it is not helpful to the question
}
var apiClient = new ApiClient();
apiClient.SetOAuthBasePath(ConfigurationManager.AppSettings["AuthServer"]);
UserInfo userInfo = apiClient.GetUserInfo(accessToken.access_token);
Account acct = userInfo.Accounts.FirstOrDefault();
FoldersApi foldersApi = new FoldersApi(apiClient);
foreach (var folder in foldersApi.List(acct.AccountId).Folders)
{
Console.WriteLine(folder.Name);
}
}
}
}
It turns out the problem was BaseUri. Posting the working code below.
var apiClient = new ApiClient();
apiClient.SetOAuthBasePath(ConfigurationManager.AppSettings["AuthServer"]);
UserInfo userInfo = apiClient.GetUserInfo(accessToken.access_token);
Account acct = userInfo.Accounts.FirstOrDefault();
apiClient.SetBasePath((acct.BaseUri + "/restapi"));
FoldersApi foldersApi = new FoldersApi(apiClient);
foreach (var folder in foldersApi.List(acct.AccountId).Folders)
{
Console.WriteLine(folder.Name);
}

Downloading file from MS teams programatically

Previously, I developed an application which downloaded a file from a corporate Sharepoint site and then performed some magic with it.
The powers that be have since migrated to MS Teams and I'm trying to update the application to use the new platform. However, I'm having all sorts of issues getting the file to download.
My old (working for Sharepoint) code uses a WebClient to retrieve the file based on credentials previously provided by the user:
private string GetSchedule(string username, string password, string domain)
{
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential(username, password, domain);
try
{
client.DownloadFile(_networkSchedulePath, tempPath);
}
catch (WebException e)
{
if (e.Message.Contains("401"))
{
StatusUpdated?.Invoke(this, new EventArgs<string>("Invalid Credentials Provided"));
Finished?.Invoke(this, null);
return null;
}
if (e.Message.Contains("404"))
{
StatusUpdated?.Invoke(this, new EventArgs<string>("File Not Found"));
Finished?.Invoke(this, null);
return null;
}
else
{
StatusUpdated?.Invoke(this, new EventArgs<string>(e.Message));
Finished?.Invoke(this, null);
return null;
}
}
}
return tempPath;
}
However, when I use this with the new teams link I'm getting a 403 Forbidden error. So is there any way to programmatically retrieve a file from MS Teams?
I was mistaken in the comments. Simply replacing the NetworkCredentials with SharePointOnlineCredentials is not the solution.
I'm not sure if the following is the "right" approach, but it works and seems pretty solid. Please give it a try:
private static string GetFile(string path, string username, string password, string domain)
{
var secureString = new SecureString();
foreach (var ch in password)
{
secureString.AppendChar(ch);
}
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
using (WebClient client = new WebClient())
{
var credentials = new SharePointOnlineCredentials(username, secureString);
client.Headers[HttpRequestHeader.Cookie] = credentials.GetAuthenticationCookie(new Uri(path));
try
{
client.DownloadFile(path, tempPath);
}
catch (WebException e)
{
// Error Handling
}
}
return tempPath;
}
Another option is to use the CSOM rather than using a webclient directly. n.b., I encountered errors at the OpenBinaryDirect() call when using the Microsoft.SharePoint.Client NuGet package and it looks like this package is wildly out of date. It appears that the one to use now is Microsoft.SharePointOnline.CSOM or Microsoft.SharePoint2019.CSOM:
private static string GetFileWithClientContext(string path, string username, string password, string domain)
{
var secureString = new SecureString();
foreach (var ch in password)
{
secureString.AppendChar(ch);
}
string tempPath = Path.GetTempFileName().Replace(".tmp", Path.GetExtension(path));
using (var context = new ClientContext(path))
{
context.Credentials = new SharePointOnlineCredentials(username, secureString);
try
{
using (var file = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, new Uri(path).AbsolutePath))
using (var outFile = System.IO.File.OpenWrite(tempPath))
{
file.Stream.CopyTo(outFile);
}
}
catch (WebException e)
{
// Error Handling
}
}
return tempPath;
}
Thanks to JLRishe for the help his answer and comments provided. However, the final solution varied from the one in his answer, which is why I'm posting it here:
The OfficeDevPnP.Core package is used extensively for this.
Firstly, the AuthenticationManager is used to get a ClientContext in terms of the specific sharepoint site that needs to be accessed. This pops a window up to allow for the MFA. Then various components are loaded in via the ClientContext object. From here, the file is fetched via Guid and dumped to disk.
private string GetSchedule()
{
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
try
{
AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager();
ClientContext ctx = authManager.GetWebLoginClientContext("https://oursite.sharepoint.com/sites/ourspecificsite/");
Web web = ctx.Web;
Microsoft.SharePoint.Client.File schedule = web.GetFileById(new Guid("ourguid"));
ctx.Load(web);
ctx.Load(schedule);
ctx.ExecuteQuery();
FileInformation fInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx, schedule.ServerRelativeUrl);
using (var fileStream = File.Create(tempPath))
{
fInfo.Stream.CopyTo(fileStream);
}
}
catch (WebException e)
{
StatusUpdated?.Invoke(this, new EventArgs<string>(e.Message));
return null;
}
return tempPath;
}
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System.IO;
using System.Linq;
namespace Answer
{
class Answer
{
static void Main(string[] args)
{
// Create Confidential Application
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("<My_Azure_Application_Client_ID>")
.WithTenantId("<My_Azure_Tenant_ID>")
.WithClientSecret("<My_Azure_Application_Client_Secret>")
.Build();
// Create an authentication provider.
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
// Configure GraphServiceClient with provider.
GraphServiceClient graphServiceClient = new GraphServiceClient(authenticationProvider);
// Get a user
var user = graphServiceClient.Users["<My_Azure_User_Name>"].Request().GetAsync().Result;
// Get the teams the user is member of
var joinedTeams = graphServiceClient.Users[user.Id].JoinedTeams.Request().GetAsync().Result;
// Get the team we are intereseted in
var team1 = joinedTeams.FirstOrDefault(t => t.DisplayName == "<TeamName_Of_Interest>");
// Get the main folders
var folders = graphServiceClient.Groups[team1.Id].Drive.Root.Children
.Request()
.GetAsync().Result;
// Get the files in the first main folder
var files = graphServiceClient.Groups[team1.Id].Drive.Items[folders[0].Id].Children
.Request()
.GetAsync().Result;
// Get the file-Data of the first file
MemoryStream fileData = graphServiceClient.Groups[team1.Id].Drive.Items[files[0].Id].Content
.Request()
.GetAsync().Result as MemoryStream;
// Save the file to the hard-disc
System.IO.File.WriteAllBytes($"C:\\{files[0].Name}", fileData.ToArray());
}
}
}

Not working example for Dialogflow V2 api

Experienced problems with C# SDK documentation which can be found here:
http://googleapis.github.io/google-cloud-dotnet/docs/Google.Cloud.Dialogflow.V2/api/Google.Cloud.Dialogflow.V2.SessionsClient.html#Google_Cloud_Dialogflow_V2_SessionsClient_Create_Google_Api_Gax_Grpc_ServiceEndpoint_Google_Cloud_Dialogflow_V2_SessionsSettings_
No reference for method ToChannelCredentials().
We cannot connect the SDK to dialogflow, even with blank project. Is this method still existing or deprecated?
using Google.Cloud.Dialogflow.V2;
using Google.Apis.Auth.OAuth2;
using Grpc.Auth;
using Grpc.Core;
...
GoogleCredential cred = GoogleCredential.FromFile("/path/to/credentials.json");
Channel channel = new Channel(
SessionsClient.DefaultEndpoint.Host, SessionsClient.DefaultEndpoint.Port, cred.ToChannelCredentials());
SessionsClient client = SessionsClient.Create(channel);
...
// Shutdown the channel when it is no longer required.
channel.ShutdownAsync().Wait();
Have you tried connecting using the service account private key ? (Json file)
Follow these steps (working example in C#)
After you create a Dialogflow agent go to the agent's settings --> General --> click on the Service Account link
You will be sent to to google cloud platform where you can create a service account
After you create a service account, there will be an option to create a KEY, create it and download the (JSON) format of it
This key will be used to connect from your C# project to the Dialogflow agent
Install Google.Cloud.Dialogflow.V2 package in your project
Create for example a Dialogflow manager class (check below for an example)
public class DialogflowManager {
private string _userID;
private string _webRootPath;
private string _contentRootPath;
private string _projectId;
private SessionsClient _sessionsClient;
private SessionName _sessionName;
public DialogflowManager(string userID, string webRootPath, string contentRootPath, string projectId) {
_userID = userID;
_webRootPath = webRootPath;
_contentRootPath = contentRootPath;
_projectId = projectId;
SetEnvironmentVariable();
}
private void SetEnvironmentVariable() {
try {
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", _contentRootPath + "\\Keys\\{THE_DOWNLOADED_JSON_FILE_HERE}.json");
} catch (ArgumentNullException) {
throw;
} catch (ArgumentException) {
throw;
} catch (SecurityException) {
throw;
}
}
private async Task CreateSession() {
// Create client
_sessionsClient = await SessionsClient.CreateAsync();
// Initialize request argument(s)
_sessionName = new SessionName(_projectId, _userID);
}
public async Task < QueryResult > CheckIntent(string userInput, string LanguageCode = "en") {
await CreateSession();
QueryInput queryInput = new QueryInput();
var queryText = new TextInput();
queryText.Text = userInput;
queryText.LanguageCode = LanguageCode;
queryInput.Text = queryText;
// Make the request
DetectIntentResponse response = await _sessionsClient.DetectIntentAsync(_sessionName, queryInput);
return response.QueryResult;
}
}
And then this can be called like this for example to get detect Intents
DialogflowManager dialogflow = new DialogflowManager("{INSERT_USER_ID}",
_hostingEnvironment.WebRootPath,
_hostingEnvironment.ContentRootPath,
"{INSERT_AGENT_ID");
var dialogflowQueryResult = await dialogflow.CheckIntent("{INSERT_USER_INPUT}");

Firebase 3: creating a custom authentication token using .net and c#

I'm trying to implement Firebase 3 Authentication mechanism using Custom Tokens (as described at https:// firebase.google.com/docs/auth/server/create-custom-tokens).
My server is ASP.NET MVC Application.
So according to the instructions (https://firebase.google.com/docs/server/setup) I've created a service account for my Firebase application and generated a key in '.p12' format.
After that according to instructions here (https://firebase.google.com/docs/auth/server/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library) I tried to generate a custom token and sign it using the key received on the previous step. For token generation I used SystemIdentityModel.Tokens.Jwt library from Microsoft, so the code looks like the following:
var now = DateTime.UtcNow;
var tokenHandler = new JwtSecurityTokenHandler();
var key = new X509AsymmetricSecurityKey(new X509Certificate2(p12path, p12pwd));
var signinCredentials = new SigningCredentials(key, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#rsa-sha256");
Int32 nowInUnixTimestamp = (Int32)(now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
var token = tokenHandler.CreateToken(
issuer: serviceAccountEmail,
audience: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
signingCredentials: signinCredentials,
subject: new ClaimsIdentity(new Claim[]
{
new Claim("sub", serviceAccountEmail),
new Claim("iat", nowInUnixTimestamp.ToString()),
new Claim("exp", (nowInUnixTimestamp + (60*60)).ToString()),
new Claim("uid", uid)
})
);
var tokenString = tokenHandler.WriteToken(token);
Then tried to sign in user in React Native application using Firebase Javascript SDK, with the following code:
//omitting initialization code
firebase.auth().signInWithCustomToken(firebaseJWT).catch(function(error) {
console.log('Error authenticating Firebase user. Code: ' + error.code + ' Message: ' + error.message);
});
But got an error from Firebase saying:
Error authenticating Firebase user. Code: auth/invalid-custom-token Message: The custom token format is incorrect. Please check the documentation.
Experimenting with adding different claims for token expiration control didn't help either.
Also I tried to generate tokens with "dvsekhvalnov/jose-jwt" library but can't get it working with "RS256" algorithm.
So the question:
Any suggestion on what am I doing wrong?
This pure .NET solution works for me, using the Org.BouncyCastle (https://www.nuget.org/packages/BouncyCastle/) and Jose.JWT (https://www.nuget.org/packages/jose-jwt/) libraries.
I followed these steps:
In the Firebase console click the 'cog' icon which is top left, next to the project name, and click 'Permissions'.
At the IAM and Admin page, click 'Service Accounts' on the left
Click 'Create Service Account' at the top, enter a 'Service Account Name', select 'Project->Editor' in the Role selection, tick the 'Furnish a new private key' checkbox and select JSON
Click 'Create' and download the Service Account JSON file and keep it safe.
Open the Service Account JSON file in a suitable text editor and put the values into the following code:
// private_key from the Service Account JSON file
public static string firebasePrivateKey=#"-----BEGIN PRIVATE KEY-----\nMIIE...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n-----END PRIVATE KEY-----\n";
// Same for everyone
public static string firebasePayloadAUD="https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit";
// client_email from the Service Account JSON file
public static string firebasePayloadISS="serviceaccountname#projectname.iam.gserviceaccount.com";
public static string firebasePayloadSUB="serviceaccountname#projectname.iam.gserviceaccount.com";
// the token 'exp' - max 3600 seconds - see https://firebase.google.com/docs/auth/server/create-custom-tokens
public static int firebaseTokenExpirySecs=3600;
private static RsaPrivateCrtKeyParameters _rsaParams;
private static object _rsaParamsLocker=new object();
void Main() {
// Example with custom claims
var uid="myuserid";
var claims=new Dictionary<string, object> {
{"premium_account", true}
};
Console.WriteLine(EncodeToken(uid, claims));
}
public static string EncodeToken(string uid, Dictionary<string, object> claims) {
// Get the RsaPrivateCrtKeyParameters if we haven't already determined them
if (_rsaParams == null) {
lock (_rsaParamsLocker) {
if (_rsaParams == null) {
StreamReader sr = new StreamReader(GenerateStreamFromString(firebasePrivateKey.Replace(#"\n","\n")));
var pr = new Org.BouncyCastle.OpenSsl.PemReader(sr);
_rsaParams = (RsaPrivateCrtKeyParameters)pr.ReadObject();
}
}
}
var payload = new Dictionary<string, object> {
{"claims", claims}
,{"uid", uid}
,{"iat", secondsSinceEpoch(DateTime.UtcNow)}
,{"exp", secondsSinceEpoch(DateTime.UtcNow.AddSeconds(firebaseTokenExpirySecs))}
,{"aud", firebasePayloadAUD}
,{"iss", firebasePayloadISS}
,{"sub", firebasePayloadSUB}
};
return Jose.JWT.Encode(payload, Org.BouncyCastle.Security.DotNetUtilities.ToRSA(_rsaParams), JwsAlgorithm.RS256);
}
private static long secondsSinceEpoch(DateTime dt) {
TimeSpan t = dt - new DateTime(1970, 1, 1);
return (long)t.TotalSeconds;
}
private static Stream GenerateStreamFromString(string s) {
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
To get this working in IIS I needed to change the application's pool identity and set the "load user profile" setting to true.
Haven't found a direct answer for the question so far, so for now ended up with the following solution:
Using instruction here generated a JSON file with service account details and created a basic Node.js server using Firebase server SDK that does generate correct custom tokens for Firebase with the following code:
var http = require('http');
var httpdispatcher = require('httpdispatcher');
var firebase = require('firebase');
var config = {
serviceAccount: {
projectId: "{projectId}",
clientEmail: "{projectServiceEmail}",
privateKey: "-----BEGIN PRIVATE KEY----- ... ---END PRIVATE KEY-----\n"
},
databaseURL: "https://{projectId}.firebaseio.com"
};
firebase.initializeApp(config);
const PORT=8080;
httpdispatcher.onGet("/firebaseCustomToken", function(req, res) {
var uid = req.params.uid;
if (uid) {
var customToken = firebase.auth().createCustomToken(uid);
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({'firebaseJWT' : customToken}));
} else {
res.writeHead(400, {'Content-Type': 'text/plain'});
res.end('No uid parameter specified');
}
});
function handleRequest(request, response){
try {
//log the request on console
console.log(request.url);
//Disptach
httpdispatcher.dispatch(request, response);
} catch(err) {
console.log(err);
}
}
//create a server
var server = http.createServer(handleRequest);
//start our server
server.listen(PORT, function(){
console.log("Server listening on: http://localhost:%s", PORT);
});
Maybe someone will find this helpful.
#Elliveny's answer worked great for me. I am using it in a .NET Core 2.0 application and have built upon the accepted answer to turn this solution into a class that can be registered as a singleton dependency in the app services container, as well as have configuration passed in via constructor so that we can leverage .NET secrets for local development configuration and environment variables for production configuration.
I have also tidied up the stream handling a bit.
Note for .NET Core devs - you'll need to use Portable.BouncyCastle
You can test your encoded results by parsing the output JWT token with Jwt.IO
using Jose;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class FirebaseTokenGenerator
{
// private_key from the Service Account JSON file
public static string firebasePrivateKey;
// Same for everyone
public static string firebasePayloadAUD = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit";
// client_email from the Service Account JSON file
public static string firebasePayloadISS;
public static string firebasePayloadSUB;
// the token 'exp' - max 3600 seconds - see https://firebase.google.com/docs/auth/server/create-custom-tokens
public static int firebaseTokenExpirySecs = 3600;
private static RsaPrivateCrtKeyParameters _rsaParams;
private static object _rsaParamsLocker = new object();
public FirebaseTokenGenerator(string privateKey, string clientEmail)
{
firebasePrivateKey = privateKey ?? throw new ArgumentNullException(nameof(privateKey));
firebasePayloadISS = clientEmail ?? throw new ArgumentNullException(nameof(clientEmail));
firebasePayloadSUB = clientEmail;
}
public static string EncodeToken(string uid)
{
return EncodeToken(uid, null);
}
public static string EncodeToken(string uid, Dictionary<string, object> claims)
{
// Get the RsaPrivateCrtKeyParameters if we haven't already determined them
if (_rsaParams == null)
{
lock (_rsaParamsLocker)
{
if (_rsaParams == null)
{
using (var streamWriter = WriteToStreamWithString(firebasePrivateKey.Replace(#"\n", "\n")))
{
using (var sr = new StreamReader(streamWriter.BaseStream))
{
var pr = new Org.BouncyCastle.OpenSsl.PemReader(sr);
_rsaParams = (RsaPrivateCrtKeyParameters)pr.ReadObject();
}
}
}
}
}
var payload = new Dictionary<string, object> {
{"uid", uid}
,{"iat", SecondsSinceEpoch(DateTime.UtcNow)}
,{"exp", SecondsSinceEpoch(DateTime.UtcNow.AddSeconds(firebaseTokenExpirySecs))}
,{"aud", firebasePayloadAUD}
,{"iss", firebasePayloadISS}
,{"sub", firebasePayloadSUB}
};
if (claims != null && claims.Any())
{
payload.Add("claims", claims);
}
return JWT.Encode(payload, Org.BouncyCastle.Security.DotNetUtilities.ToRSA(_rsaParams), JwsAlgorithm.RS256);
}
private static long SecondsSinceEpoch(DateTime dt)
{
TimeSpan t = dt - new DateTime(1970, 1, 1);
return (long) t.TotalSeconds;
}
private static StreamWriter WriteToStreamWithString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return writer;
}
}
The #Elliveny's code worked for me in locally but in azure throws an error : "The system cannot find the file specified". Due that I have changed a little bit the code and now works in both servers.
private string EncodeToken(string uid, Dictionary<string, object> claims)
{
string jwt = string.Empty;
RsaPrivateCrtKeyParameters _rsaParams;
using (StreamReader sr = new StreamReader(GenerateStreamFromString(private_key.Replace(#"\n", "\n"))))
{
var pr = new Org.BouncyCastle.OpenSsl.PemReader(sr);
_rsaParams = (RsaPrivateCrtKeyParameters)pr.ReadObject();
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
Dictionary<string, object> payload = new Dictionary<string, object> {
{"claims", claims}
,{"uid", uid}
,{"iat", secondsSinceEpoch(DateTime.UtcNow)}
,{"exp", secondsSinceEpoch(DateTime.UtcNow.AddSeconds(firebaseTokenExpirySecs))}
,{"aud", firebasePayloadAUD}
,{"iss", client_email}
,{"sub", client_email}
};
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters(_rsaParams);
rsa.ImportParameters(rsaParams);
jwt = JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
return jwt;
}

Uploading objects to google cloud storage buckets in c#

Can someone please provide an example of how to use Google.Apis.Storage.v1 for uploading files to google cloud storage in c#?
I found that this basic operation is not as straight forward as you might expect. Google's documentation about it's Storage API is lacking in information about using it in C# (or any other .NET language). Searching for 'how to upload file to google cloud storage in c#' didn't exactly help me, so here is my working solution with some comments:
Preparation:
You need to create OAuth2 account in your Google Developers Console - go to Project/APIs & auth/Credentials.
Copy Client ID & Client Secret to your code. You will also need your Project name.
Code (it assumes that you've added Google.Apis.Storage.v1 via NuGet):
First, you need to authorize your requests:
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = clientId;
clientSecrets.ClientSecret = clientSecret;
//there are different scopes, which you can find here https://cloud.google.com/storage/docs/authentication
var scopes = new[] {#"https://www.googleapis.com/auth/devstorage.full_control"};
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets,scopes, "yourGoogle#email", cts.Token);
Sometimes you might also want to refresh authorization token via:
await userCredential.RefreshTokenAsync(cts.Token);
You also need to create Storage Service:
var service = new Google.Apis.Storage.v1.StorageService();
Now you can make requests to Google Storage API.
Let's start with creating a new bucket:
var newBucket = new Google.Apis.Storage.v1.Data.Bucket()
{
Name = "your-bucket-name-1"
};
var newBucketQuery = service.Buckets.Insert(newBucket, projectName);
newBucketQuery.OauthToken = userCredential.Result.Token.AccessToken;
//you probably want to wrap this into try..catch block
newBucketQuery.Execute();
And it's done. Now, you can send a request to get list of all of your buckets:
var bucketsQuery = service.Buckets.List(projectName);
bucketsQuery.OauthToken = userCredential.Result.Token.AccessToken;
var buckets = bucketsQuery.Execute();
Last part is uploading new file:
//enter bucket name to which you want to upload file
var bucketToUpload = buckets.Items.FirstOrDefault().Name;
var newObject = new Object()
{
Bucket = bucketToUpload,
Name = "some-file-"+new Random().Next(1,666)
};
FileStream fileStream = null;
try
{
var dir = Directory.GetCurrentDirectory();
var path = Path.Combine(dir, "test.png");
fileStream = new FileStream(path, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload,fileStream,"image/png");
uploadRequest.OauthToken = userCredential.Result.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
And bam! New file will be visible in you Google Developers Console inside of selected bucket.
You can use Google Cloud APIs without SDK in the following ways:
Required api-key.json file
Install package Google.Apis.Auth.OAuth2 in order to authorize the
HTTP web request
You can set the default configuration for your application in this
way
I did the same using .NET core web API and details are given below:
Url details:
"GoogleCloudStorageBaseUrl": "https://www.googleapis.com/upload/storage/v1/b/",
"GoogleSpeechBaseUrl": "https://speech.googleapis.com/v1/operations/",
"GoogleLongRunningRecognizeBaseUrl": "https://speech.googleapis.com/v1/speech:longrunningrecognize",
"GoogleCloudScope": "https://www.googleapis.com/auth/cloud-platform",
public void GetConfiguration()
{
// Set global configuration
bucketName = _configuration.GetValue<string>("BucketName");
googleCloudStorageBaseUrl = _configuration.GetValue<string>("GoogleCloudStorageBaseUrl");
googleSpeechBaseUrl = _configuration.GetValue<string>("GoogleSpeechBaseUrl");
googleLongRunningRecognizeBaseUrl = _configuration.GetValue<string>("GoogleLongRunningRecognizeBaseUrl");
// Set google cloud credentials
string googleApplicationCredentialsPath = _configuration.GetValue<string>("GoogleCloudCredentialPath");
using (Stream stream = new FileStream(googleApplicationCredentialsPath, FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(stream).CreateScoped(_configuration.GetValue<string>("GoogleCloudScope"));
}
Get Oauth token:
public string GetOAuthToken()
{
return googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync("https://accounts.google.com/o/oauth2/v2/auth", CancellationToken.None).Result;
}
To upload file to cloud bucket:
public async Task<string> UploadMediaToCloud(string filePath, string objectName = null)
{
string bearerToken = GetOAuthToken();
byte[] fileBytes = File.ReadAllBytes(filePath);
objectName = objectName ?? Path.GetFileName(filePath);
var baseUrl = new Uri(string.Format(googleCloudStorageBaseUrl + "" + bucketName + "/o?uploadType=media&name=" + objectName + ""));
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + bearerToken);
client.Headers.Add(HttpRequestHeader.ContentType, "application/octet-stream");
byte[] response = await Task.Run(() => client.UploadData(baseUrl, "POST", fileBytes));
string responseInString = Encoding.UTF8.GetString(response);
return responseInString;
}
}
In order to perform any action to the cloud API, just need to make a HttpClient get/post request as per the requirement.
Thanks
This is for Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1), but appears to be a bit simpler to perform an upload now. I started with the Client libraries "Getting Started" instructions to create a service account and bucket, then experimented to find out how to upload an image.
The process I followed was:
Sign up for Google Cloud free trial
Create a new project in Google Cloud (remember the project name\ID for later)
Create a Project Owner service account - this will result in a json file being downloaded that contains the service account credentials. Remember where you put that file.
The getting started docs get you to add the path to the JSON credentials file into an environment variable called GOOGLE_APPLICATION_CREDENTIALS - I couldn't get this to work through the provided instructions. Turns out it is not required, as you can just read the JSON file into a string and pass it to the client constructor.
I created an empty WPF project as a starting point, and a single ViewModel to house the application logic.
Install the Google.Cloud.Storage.V1 nuget package and it should pull in all the dependencies it needs.
Onto the code.
MainWindow.xaml
<StackPanel>
<Button
Margin="50"
Height="50"
Content="BEGIN UPLOAD"
Click="OnButtonClick" />
<ContentControl
Content="{Binding Path=ProgressBar}" />
</StackPanel>
MainWindow.xaml.cs
public partial class MainWindow
{
readonly ViewModel _viewModel;
public MainWindow()
{
_viewModel = new ViewModel(Dispatcher);
DataContext = _viewModel;
InitializeComponent();
}
void OnButtonClick(object sender, RoutedEventArgs args)
{
_viewModel.UploadAsync().ConfigureAwait(false);
}
}
ViewModel.cs
public class ViewModel
{
readonly Dispatcher _dispatcher;
public ViewModel(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
ProgressBar = new ProgressBar {Height=30};
}
public async Task UploadAsync()
{
// Google Cloud Platform project ID.
const string projectId = "project-id-goes-here";
// The name for the new bucket.
const string bucketName = projectId + "-test-bucket";
// Path to the file to upload
const string filePath = #"C:\path\to\image.jpg";
var newObject = new Google.Apis.Storage.v1.Data.Object
{
Bucket = bucketName,
Name = System.IO.Path.GetFileNameWithoutExtension(filePath),
ContentType = "image/jpeg"
};
// read the JSON credential file saved when you created the service account
var credential = Google.Apis.Auth.OAuth2.GoogleCredential.FromJson(System.IO.File.ReadAllText(
#"c:\path\to\service-account-credentials.json"));
// Instantiates a client.
using (var storageClient = Google.Cloud.Storage.V1.StorageClient.Create(credential))
{
try
{
// Creates the new bucket. Only required the first time.
// You can also create buckets through the GCP cloud console web interface
storageClient.CreateBucket(projectId, bucketName);
System.Windows.MessageBox.Show($"Bucket {bucketName} created.");
// Open the image file filestream
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
{
ProgressBar.Maximum = fileStream.Length;
// set minimum chunksize just to see progress updating
var uploadObjectOptions = new Google.Cloud.Storage.V1.UploadObjectOptions
{
ChunkSize = Google.Cloud.Storage.V1.UploadObjectOptions.MinimumChunkSize
};
// Hook up the progress callback
var progressReporter = new Progress<Google.Apis.Upload.IUploadProgress>(OnUploadProgress);
await storageClient.UploadObjectAsync(
newObject,
fileStream,
uploadObjectOptions,
progress: progressReporter)
.ConfigureAwait(false);
}
}
catch (Google.GoogleApiException e)
when (e.Error.Code == 409)
{
// When creating the bucket - The bucket already exists. That's fine.
System.Windows.MessageBox.Show(e.Error.Message);
}
catch (Exception e)
{
// other exception
System.Windows.MessageBox.Show(e.Message);
}
}
}
// Called when progress updates
void OnUploadProgress(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case Google.Apis.Upload.UploadStatus.Starting:
ProgressBar.Minimum = 0;
ProgressBar.Value = 0;
break;
case Google.Apis.Upload.UploadStatus.Completed:
ProgressBar.Value = ProgressBar.Maximum;
System.Windows.MessageBox.Show("Upload completed");
break;
case Google.Apis.Upload.UploadStatus.Uploading:
UpdateProgressBar(progress.BytesSent);
break;
case Google.Apis.Upload.UploadStatus.Failed:
System.Windows.MessageBox.Show("Upload failed"
+ Environment.NewLine
+ progress.Exception);
break;
}
}
void UpdateProgressBar(long value)
{
_dispatcher.Invoke(() => { ProgressBar.Value = value; });
}
// probably better to expose progress value directly and bind to
// a ProgressBar in the XAML
public ProgressBar ProgressBar { get; }
}
Use of Google.Apis.Storage.v1 for uploading files using SDK to google cloud storage in c#:
Required api-key.json file
Install the package Google.Cloud.Storage.V1; and Google.Apis.Auth.OAuth2;
The code is given below to upload the file to the cloud
private string UploadFile(string localPath, string objectName = null)
{
string projectId = ((Google.Apis.Auth.OAuth2.ServiceAccountCredential)googleCredential.UnderlyingCredential).ProjectId;
try
{
// Creates the new bucket.
var objResult = storageClient.CreateBucket(projectId, bucketName);
if (!string.IsNullOrEmpty(objResult.Id))
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus1 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Google.GoogleApiException ex)
{
// Error code =409, means bucket already created/exist then upload file in the bucket
if (ex.Error.Code == 409)
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus2 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return objectName;
}
To set the credentials
private bool SetStorageCredentials()
{
bool status = true;
try
{
if (File.Exists(credential_path))
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
using (Stream objStream = new FileStream(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"), FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(objStream);
// Instantiates a client.
storageClient = StorageClient.Create();
channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host, googleCredential.ToChannelCredentials());
}
else
{
DialogResult result = MessageBox.Show("File " + Path.GetFileName(credential_path) + " does not exist. Please provide the correct path.");
if (result == System.Windows.Forms.DialogResult.OK)
{
status = false;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
status = false;
}
return status;
}
I used SDK in one of my window application. You can use the same code according to your needs/requirements.
You'll be happy to know it still works in 2016...
I was googling all over using fancy key words like "google gcp C# upload image", until I just plain asked the question: "How do I upload an image to google bucket using C#"... and here I am. I removed the .Result in the user credential, and this was the final edit that worked for me.
// ******
static string bucketForImage = ConfigurationManager.AppSettings["testStorageName"];
static string projectName = ConfigurationManager.AppSettings["GCPProjectName"];
string gcpPath = Path.Combine(Server.MapPath("~/Images/Gallery/"), uniqueGcpName + ext);
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = ConfigurationManager.AppSettings["GCPClientID"];
clientSecrets.ClientSecret = ConfigurationManager.AppSettings["GCPClientSc"];
var scopes = new[] { #"https://www.googleapis.com/auth/devstorage.full_control" };
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, ConfigurationManager.AppSettings["GCPAccountEmail"], cts.Token);
var service = new Google.Apis.Storage.v1.StorageService();
var bucketToUpload = bucketForImage;
var newObject = new Google.Apis.Storage.v1.Data.Object()
{
Bucket = bucketToUpload,
Name = bkFileName
};
FileStream fileStream = null;
try
{
fileStream = new FileStream(gcpPath, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload, fileStream, "image/"+ ext);
uploadRequest.OauthToken = userCredential.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
// ******
Here is the link to their official C# example of ".NET Bookshelf App" using Google Cloud storage.
https://cloud.google.com/dotnet/docs/getting-started/using-cloud-storage
Source on github:
https://github.com/GoogleCloudPlatform/getting-started-dotnet/blob/master/aspnet/3-binary-data/Services/ImageUploader.cs
https://github.com/GoogleCloudPlatform/getting-started-dotnet/tree/master/aspnet/3-binary-data
Nuget
https://www.nuget.org/packages/Google.Cloud.Storage.V1/
Here are 2 examples that helped me to upload files to a bucket in Google Cloud Storage with Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1):
Upload files to Google cloud storage using c#
Uploading .csv Files to Google Cloud Storage using C# .Net
I got both working on a C# Console Application just for testing purposes.
#February 2021
string _projectId = "YOUR-PROJECT-ID-GCP"; //ProjectID also present in the json file
GoogleCredential _credential = GoogleCredential.FromFile("credential-cloud-file-123418c9e06c.json");
/// <summary>
/// UploadFile to GCS Bucket
/// </summary>
/// <param name="bucketName"></param>
/// <param name="localPath">my-local-path/my-file-name</param>
/// <param name="objectName">my-file-name</param>
public void UploadFile(string bucketName, string localPath, string objectName)
{
var storage = StorageClient.Create(_credential);
using var fileStream = File.OpenRead(localPath);
storage.UploadObject(bucketName, objectName, null, fileStream);
Console.WriteLine($"Uploaded {objectName}.");
}
You get the credentials JSON file from the google cloud portal where you create a bucket under your project..
Simple, with auth:
private void SaveFileToGoogleStorage(string path, string? fileName, string ext)
{
var filePath = Path.Combine(path, fileName + ext);
var gcCredentialsPath = Path.Combine(Environment.CurrentDirectory, "gc_sa_key.json");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", gcCredentialsPath);
var gcsStorage = StorageClient.Create();
using var f = File.OpenRead(filePath);
var objectName = Path.GetFileName(filePath);
gcsStorage.UploadObject(_bucketName, objectName, null, f);
Console.WriteLine($"Uploaded {objectName}.");
}

Categories