I am using ASP.NET Web API and Google.Apis.Drive.v2 Client Library for .NET to upload files to users Drive.
All examples of using the Drive Client Library for .NET require a authentication flow. But how should I create the DriveService when I already know the access token?
Despite the fact that have been 2 years since the question has been asked, today I've encountered the same situation and my solution is:
var valid_token = "Pass_the_valid_token_here";
var token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse()
{
AccessToken = valid_token,
ExpiresInSeconds = 3600,
Issued = DateTime.Now
};
var fakeflow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "fakeClientId",
ClientSecret = "fakeClientSecret"
}
});
UserCredential credential = new UserCredential(fakeflow, "fakeUserId", token);
var serviceInitializer = new BaseClientService.Initializer()
{
//ApplicationName = "Storage Sample",
HttpClientInitializer = credential
};
DriveService service = new DriveService(serviceInitializer);
Update
You could create your own custom token but the issue with this is going to be that the client library will not be able to refresh your access without the refresh token.
var token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse()
{
AccessToken = valid_token,
ExpiresInSeconds = 3600,
Issued = DateTime.Now
};
var authorization = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "lientId",
ClientSecret = "ClientSecret"
}
});
var credential = new UserCredential(authorization, "user", token);
The issue you are going to have with this is that the client library is not going to be able refersh the access token after it has expired since you are not supplying a refresh token its only going to work for an hour.
The answer from Svetoslav Georgiev has so far worked well for me - Can't thank you enough. Google really don't help themselves with the lack of .Net (Asp Core) samples etc. Anway, one problem I did run into was that of referer restriction, so a addition/slight modification to the answer - Once you have the "service" and want to say upload a file, you need to set the referer on a buried HttpClient property...
FilesResource.CreateMediaUpload uploadRequest;
byte[] byteArray = Encoding.UTF8.GetBytes(html);
using (var stream = new MemoryStream(byteArray))
{
uploadRequest = service.Files.Create(fileMetadata, stream, "text/html");
uploadRequest.Service.HttpClient.DefaultRequestHeaders.Referrer = new Uri($"{baseUrl}");
uploadRequest.Fields = "id";
var progress = uploadRequest.Upload();
if (progress.Exception != null)
{
throw progress.Exception;
}
var file = uploadRequest.ResponseBody;
.... do what you will with file ....
}
Related
I have a xamarin app --> azureFunction --->BlobStorage. so far so good.
The AzureFunction is set with AuthorizationLevel.Function.
I have set the azure function Managed identity "ON"
I have assigned a role to the BlobStorage (Blob data Contributor)
I can successfully call the function using postman using the function key.
I would like to store the functionKey in the KeyVault and call it from my mobile app
Question
As anybody got a walkthrough and snippet how to integrate the keyvault with a function key and call it from a mobile app (xamarin forms) c#?
I do not want to hardcode any keys in my mobile app.
I would be very grateful.Lots of googling and nothing.
thanks
Suppose your requirement is call the function from the code. Maybe you could refer to the below code.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("your Secret Identifier")
.ConfigureAwait(false);
string functionkey = secret.Value;
string functionhost = "https://your function.azurewebsites.net/api/function name";
var param = new Dictionary<string, string>() { { "code", functionkey } ,{ "name","george"} };
Uri functionurl = new Uri(QueryHelpers.AddQueryString(functionhost, param));
var request = (HttpWebRequest)WebRequest.Create(functionurl);
var response = (HttpWebResponse)request.GetResponse();
string responseString;
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
responseString = reader.ReadToEnd();
Console.WriteLine(responseString);
}
}
I'm new with Xamarin.Forms, and I'm finding a way to store data in App like: token, username. Now, I'm trying to use SecureStorgae, but the function getValue doesn't work, and I have no idea why.
My code:
public async Task CheckLogin(string usernameString, string passwordString)
{
using (var client = new HttpClient())
{
string url = "myUrl";
var json = JsonConvert.SerializeObject(new { username = usernameString, password=passwordString });
HttpContent content = new StringContent(json,Encoding.UTF8, "application/json");
var response = await client.PostAsync(url,content);
if (response.IsSuccessStatusCode)
{
var rs = JsonConvert.DeserializeObject<LoginResult>(response.Content.ReadAsStringAsync().Result);
var token = rs.result.token;
CrossSecureStorage.Current.SetValue("SessionToken",token);
CrossSecureStorage.Current.SetValue("Username", rs.result.userName);
var token1 = CrossSecureStorage.Current.GetValue("SessionToken");
await Navigation.PushAsync(new Home());
}
}
}
When my app is running, I can't get the value of SessionToken.
in iOS
Open the Entitlements.plist file and make sure that "Enable Keychain Access Groups" is checked. Also ensure that in Project->Options->iOS Bundle Signing, the Entitlements.plist is selected in Custom Entitlements for iPhoneSimulator platform.
in Android
It is required that the password is set by the application prior to use.
SecureStorageImplementation.StoragePassword = "Your Password";
For more detail you can access here
I have two identityservers and one Web API.
What Im trying to do is having the API authenticate with one or both of the IdentityServers and being able to switch if one goes down. If possbile I would also like to be able to add a new IdentityServer at runtime.
Is there any best practice here?
As of now it looks like this.
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = $"http://localhost:5000",
ScopeName = "my.scope",
RequireHttpsMetadata = false,
ScopeSecret = "secret",
});
If I shut down the IdentityServer at port 5000 I can't use the API anymore. Which is to be expected.
Im not sure if this is a good way to solve it. But it's one way.
I ask my routing service for the "first identityservice" to set the Authroity in options.
And then I add a custom IntrospectionBackChannelHandler
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = $"http://{v.Address}:{v.Port}",
IntrospectionBackChannelHandler = new CustomIntrospectionBackChannelHandler(consulService)
Since all my identity servers look the same but are on different addresses I dont really have to bother to do the Authority thing again.
Inside the custom Introspect.... I check each introspect and send it to the "correct" identityserver. If its not working I try another identityserver.
var qs = await request.Content.ReadAsStringAsync();
var queryDic = QueryHelpers.ParseQuery(await request.Content.ReadAsStringAsync());
var token = queryDic["token"];
var client_id = queryDic["client_id"];
var client_secret = queryDic["client_secret"];
var iRequest = new IntrospectionRequest
{
ClientId = client_id,
ClientSecret = client_secret,
TokenTypeHint = "access_token",
Token = token
};
IntrospectionResponse result = null;
var svc = await _Consul.GetService(OrbitServices.IdentityServer);
result = await TrySendAsync(iRequest, svc);
if (!result.IsActive && result.IsError)
{
svc = await _Consul.GetService(OrbitServices.IdentityServer, true);
result = await TrySendAsync(iRequest, svc);
}
var message = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(result.Raw, Encoding.UTF8, "application/json")
};
return message;
I've implemented simple Google+ authentication on my MVC5 app and I'd like to access their google calendar. How do I do this using the MVC identity system and my already authenticated user?
Dim authGOps = New GooglePlusAuthenticationOptions() With {
.Caption = "Google+",
.ClientId = "MYCLIENTRID",
.ClientSecret = "MYCLIENTSECRET",
.Provider = New GooglePlusAuthenticationProvider() With {
.OnAuthenticated = Async Function(context)
context.Identity.AddClaim(New Claim(GooglePlusAccessTokenClaimType, context.AccessToken))
End Function
}
}
authGOps.Scope.Add("https://www.googleapis.com/auth/calendar")
app.UseGooglePlusAuthentication(authGOps)
Getting the calendar service:
Dim calendarService = New CalendarService(New Google.Apis.Services.BaseClientService.Initializer() With {
WHAT GOES HERE TO AUTHENTICATE USING MY OLD AUTH CEDENTIALS?
}
So I as well would love to use the Service as it's documented almost everywhere, but I found a workaround to at least getting the data and not having to login again.
Make sure to Nuget Json.Net to deserialize and strongly type. Otherwise you'll get a Json string to manage.
It's in C#, but I'm sure the translation won't be too difficult. Hope it helps!
var claimsIdentity = User.Identity as ClaimsIdentity;
var claims = claimsIdentity.Claims;
var accessTokenClaim = claims.FirstOrDefault(x => x.Type == GooglePlusAccessTokenClaimType);
if (accessTokenClaim != null)
{
string calendarUrl = "https://www.googleapis.com/calendar/v3/users/me/calendarList?access_token=" + Uri.EscapeDataString(accessTokenClaim.Value);
using(var client = new HttpClient())
{
var response = await client.GetAsync(calendarUrl);
var calendarList = JsonConvert.DeserializeObject<CalendarList>(await response.Content.ReadAsStringAsync());
}
}
I'm using Google Calendar API V3, with OAuth2 & .NET.
my authentication is by Service Account, since i need to run it as a service, without user interface.
I've managed, after a lot of struggle to authenticate with the credentials, but for some reason i can't create an event on my calendar (& yes, i shared it with my self...).
i found a lot of questions regarding some same issues, but all in php, which i don't really know or think it will help me.
i seek for some help. Thanks
String serviceAccountEmail = "XXX#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"key.p12", "notasecret", X509KeyStorageFlags.MachineKeySet |X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
Event e = new Event()
{
Summary = "Appointment1",
Location = "42.138679, -88.045519",
Start = new EventDateTime()
{
DateTime = DateTime.Now,
TimeZone = "Asia/Jerusalem"
},
End = new EventDateTime()
{
DateTime = DateTime.Now.AddDays(1),
TimeZone = "Asia/Jerusalem"
},
};
Event createdEvent = service.Events.Insert(e, "primary").Execute();
For some reason, the Insert event to a "primary" calendar, didn't do the job.
Instead, i wrote the following code, which allowed me to write the event.
var list = service.CalendarList.List().Execute().Items;
service.Events.Insert(e, list[0].Id).Execute();
This is my solution for this problem, I also agree with Craig here that the API is not well organized. (saying this after working with the amazing API of maps).
Perhaps try specifying the user programmatically, rather than sharing the calendar with your service account e-mail? The following worked in my application:
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = "youremail#yourdomain.com",
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// ... Define the event
service.Events.Insert(e, "primary").Execute();