X509Certificate2 Access denied error - asp.net

EDIT: This is my final code after taking your(#DalmTo) advice:
public static AnalyticsService Authenticate()
{
string[] scopes = new string[] { AnalyticsService.Scope.Analytics,
AnalyticsService.Scope.AnalyticsManageUsers};
string keyFilePath = #"G:\PleskVhosts\mydomainname\httpdocs\App_Data\API Project-2f74017ed363.p12"; // found in developer console
string serviceAccountEmail = "myconsoleapiaccount#developer.gserviceaccount.com"; // found in developer console
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) { Scopes = scopes }.FromCertificate(certificate));
AnalyticsService service = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "myappname",
});
Thank you so much for the tutorial you linked me, I examined it carefully and your code was so much less work than trying to do it manually. I am aware of the tips you have given me, and I have necessary permissions for that account in my Google Analytics account. I followed your tutorial, and it works like a charm in my localhost, but when I publish my website, this is the current error I am getting this error:
{"Message":"Access is denied.\r\n","StackTrace":" at System.Security.Cryptography.X509Certificates.X509Store.Add(X509Certificate2 certificate)\r\n at Thunder.Main.Default.Authenticate()\r\n at Thunder.Main.Default.GetChartData()","ExceptionType":"System.Security.Cryptography.CryptographicException"}
I have contacted with my hosting provider, and they are telling me that they won't be making changes in IIS, I've added trust level full tag to the web.config, but I am still getting this error.I am currently working on it, but if you have any advices, please let me know. I will update here If I can come up with a solution. Thanks!

As mentioned above you need to configure IIS but as our case, some time you need to check the permission of the following folder:
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
If you set X509KeyStorageFlags parameter it will create a key file in this folder. In my case there was a difference in permission of this folder. Pool account was not added in the mentioned folder.

You really are making things harder for yourself here. I am not sure whats wrong with your code. TBH I have never tried doing it manually because I use the client library
NuGet Package
PM> Install-Package Google.Apis.Analytics.v3
Authentication with a service account.
You need to send the full path to the key file or sometimes it complains. Ideally it should be out side of the web root but it needs to be someplace that the webserver has access to read it since you are using asp for this.
string[] scopes =
new string[] {
AnalyticsService.Scope.Analytics, // view and manage your Google Analytics data
AnalyticsService.Scope.AnalyticsManageUsers}; // View Google Analytics data
string keyFilePath = #"c:\file.p12" ; // found in developer console
string serviceAccountEmail = "xx#developer.gserviceaccount.com"; // found in developer console
//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail)
{Scopes = scopes }.FromCertificate(certificate));
Creating Service
You pass the credential created above to the service. All of your requests will then go though the service.
AnalyticsService service = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Analytics API Sample",
});
Tips
For a service account to work with Google Analytics it must have access to your Google Analytics account. Go to the Google Analytics website admin section create a new user at the account level it must be the account level. Did I mention it wont work if it isn't the account level.
Code is taken from my tutorial series. Google Analtics with C# enjoy

Related

How to get external login profile picture from Microsoft account in asp.net core

how can I get profile picture from Microsoft account using Microsoft.AspNetCore.Authentication.Facebook library? I tried using Claims, but they don't have profile picture value... I also tried looking in account's source control by checking image url, but I noticed that the url is made of some parameters that I can't get with claims, so I can't construct url like I can with facebook... Can someone can help me?
You can obtain the profile picture from Microsoft accounts by using Microsoft Graph:
https://developer.microsoft.com/en-us/graph/quick-start
Specific instructions on how to request the profile picture:
https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/profilephoto_get
If you follow the quick start (select asp.net, click "Get an app ID and secret" and download the sample code), it's easy to obtain the data like so:
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
var photoStream = await graphService.GetCurrentUserPhotoStreamAsync(graphClient);
EDIT: Sorry, forgot the asp.net core part (it doesn't seem that Microsoft.Identity.Client is available for asp.net core).
In ExternalLoginCallback you can obtain the access token from the ExternalLoginInfo object returned by var info = await _signInManager.GetExternalLoginInfoAsync();
Remember to set SaveTokens to true when configuring authentication (otherwise the access token won't be available):
services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["ExternalProviders:Microsoft:ClientId"];
options.ClientSecret = Configuration["ExternalProviders:Microsoft:ClientSecret"];
options.SaveTokens = true;
...
Then it's just a matter of making a http request - something like this:
var httpClient = new HttpClient();
httpClient.SetBearerToken(info.AuthenticationTokens.Where(t => t.Name.Equals("access_token")).First().Value);
var pictureResult = httpClient.GetAsync("https://graph.microsoft.com/v1.0/me/photo/$value").Result;

Using WebClient to get a intranet files

In our I have company intranet a server, that is responsible for storing files. Initially, the server had to operate only in an intranet environment, but now there is a need to share files with external web applications. Making this server accessible from the internet is not an option.
I want to create a ASP.NET MVC solution that uses the WebClient to get these files from the intranet server and send back them to the user through FileResult of the external app. This client would be provided with custom domain user credentials. So far I have tried to create a CredentialCache class, set correct credentials and append it to WebClients Credentials property like in the following code:
public ActionResult Download(int id, string fileName)
{
var fileService = new FilesService();
var documentUrl = fileService.GetUrlFileByFileId(id);
string filePath = "http://my.intranet.com/" + documentUrl;
var fileNameFromUrl = filePath.Substring(filePath.LastIndexOf("\\") + 1);
byte[] filedata;
CredentialCache cc = new CredentialCache();
cc.Add(new Uri("http://my.intranet.com/"),
"ntlm",
new NetworkCredential("myUserName", "myPassword", "myDomain"));
using (var client = new WebClient())
{
client.Credentials = cc;
filedata = client.DownloadData(filePath);
}
string contentType = MimeMapping.GetMimeMapping(filePath);
var cd = new ContentDisposition
{
FileName = fileName,
Inline = false
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
According to the question posted in Domain credentials for a WebClient class don't work it should work, but it’s not. It’s running only if I run the problem on localhost, but when I publish my solution on a test server, it return 401 error. My question is did how to get this working? And is it possible to download files through this method?
UPDATE--- I've published my test app on another server and it started to working. Now the test app is on another server than the server That stores files. Any ideas why it's not working when both are on the same machine?
401 error is unauthorized, so perhaps the issue is related to permissions. Are you sure the user account you are using to login to that folder has the proper access?
Ok, I found the solution on this site: https://blogs.msdn.microsoft.com/distributedservices/2009/11/10/wcf-calling-wcf-service-hosted-in-iis-on-the-same-machine-as-client-throws-authentication-error/
The solution was to add an registry entry and add my web apps to this entry to allow back connections.

Error:"invalid_grant", Description:"Invalid JWT: Token must be a short-lived token and in a reasonable timeframe", Uri:""

I am trying to access google-calendar with the help of google service account
but i got belloing error
An exception of type 'Google.Apis.Auth.OAuth2.Responses.TokenResponseException' occurred in Google.Apis.dll but was not handled in user code
The error I am getting: "invalid_grant", Description:"Invalid JWT: Token must be a short-lived token and in a reasonable timeframe", Uri:""
string credPath = "key path";
String serviceAccountEmail = xxxx#developer.gserviceaccount.com";
var certificate = new X509Certificate2(credPath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { CalendarService.Scope.CalendarReadonly,
CalendarService.Scope.Calendar}
}.FromCertificate(certificate));
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "HRTool",
});
var events = service.Events.List("my calaender id").Execute();
Invalid grant
When you try to use a refresh token, the following returns you an invalid_grant error:
Your server's clock is not in sync with network time protocol - NTP.
The refresh token limit has been exceeded.
First, kindly check the synchronization problem with the server clock, see the poor synchronization of the computer's clock answer for additional information. Second, check handling of refresh token and the old tokens. Some flows include additional steps, such as using refresh tokens to acquire new access tokens. For detailed information about flows for various types of applications, see Google's OAuth 2.0 documentation.
Hope this helps!
If you are getting the error of "Invalid JWT Signature." and if you are using the P12 certificate then confirm the P12 is correct or not for the Client Key you have used.
If you are getting the error of "Invalid JWT Signature." This is the error caused by some other plugin which you just installed check. I solved by removing rank math plugin as after this plugin install the elementor update was not working.

Google Drive APi with clean WEB API 2

i wanted to use the Google Drive API along with a simple WEB API 2 - Project.
Somehow the GoogleWebAuthorizationBroker.cs is missing.
What i use:
Visual Studio 2013 Update 4
Empty Template with WEB API
My steps:
Creating the empty project including WEB API
building the project
updating packages via Nuget Packager
Install-Package Google.Apis.Drive.v2 (using this guide: https://developers.google.com/drive/web/quickstart/quickstart-cs)
Copy and Paste the code from the above link into a clean api-controller:
public IEnumerable<string> Get()
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "228492645857-5599mgcfnhrr74a7er1do1chpam4rnbt.apps.googleusercontent.com",
ClientSecret = "onoyJQaUazQK4VsKUjD63sDu",
},
new[] { DriveService.Scope.Drive },
"user",
CancellationToken.None).Result;
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
File body = new File();
body.Title = "My document";
body.Description = "A test document";
body.MimeType = "text/plain";
byte[] byteArray = System.IO.File.ReadAllBytes(#"C:\Projects\VS\DataAnime\DataAnime\document.txt");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "text/plain");
request.Upload();
File file = request.ResponseBody;
return new string[] { file.Id, "value2" };
}
building
6.1 Error: GoogleWebAuthorizationBroker.cs is missing
6.2 Google says following error in browser:
That’s an error.
Error: redirect_uri_mismatch
Application: Project Default Service Account
You can email the developer of this application at: xxxx#gmail.com
The redirect URI in the request: http://example.com:63281/authorize/ did not match a registered
redirect URI.
http://example.com:63281/authorize/ was neither the url i am using for my project nor the url i registered in my developer console (this errorshowing-port is changeing everytime i run this project.
Has anyone an idea why is that?
No other sources helped fixing this weird issue.
I solved it by creating a new project on https://console.developers.google.com for a native software instead of a web-client project, even i am using a web client.
There is just one weird thing:
If i debug my code, it still says that GoogleWebAuthorizationBroker.cs is missing.
Without debugging i can do everything i want.
Thank you very much for your help.

Publishing with Core Service and Impersonation

I have a Tridion Core Service Web Application to publish pages. When logged into the server and running it from there via a browser client calling a web service with ajax it works fine. However, when I run the application from my desktop it does nothing, and also throws no error messages.
*Edit:
The Web App hosting the web service is running as an 'Application' under the Tridion 2011 CMS website. This is done to avoid cross-domain ajax issues/
Update: The code below is working fine - both with the impersonate and also with Nick's solution. My issue was actually in how I was calling the web service from jQuery and using the appropriate URL. I am leaving the code and question so maybe it will help others.
My code is:
string binding = "wsHttp_2011";
using (var client = new SessionAwareCoreServiceClient(binding))
{
client.Impersonate("company\\cms_svc");
// ** Get Items to Publish
List<string> itemsToPublish = GetItemsToPublish(publishItem.TcmUri, client);
PublishInstructionData instruction = new PublishInstructionData
{
ResolveInstruction = new ResolveInstructionData() { IncludeChildPublications = false },
RenderInstruction = new RenderInstructionData()
};
PublicationTargetData pubtarget = (PublicationTargetData)client.Read(publishItem.PubTargetUri, readoptions);
List<string> target = new List<string>();
target.Add(pubtarget.Id);
client.Publish(itemsToPublish.ToArray(), instruction, target.ToArray(), GetPublishPriority(publishItem.Priority), readoptions);
}
Have at look at this page on SDL Live Content, which explains various types of scenarios for connecting as different users:
http://sdllivecontent.sdl.com/LiveContent/content/en-US/SDL_Tridion_2011_SPONE/task_87284697A4BB423AAD5387BBD6884735
As per the docs, instead of impersonation you may want to establish your Core Service connection as follows using NetworkCredential:
using (ChannelFactory<ISessionAwareCoreService> factory =
new ChannelFactory<ISessionAwareCoreService>("netTcp_2011"))
{
NetworkCredential networkCredential =
new NetworkCredential("username", "password", "domain");
factory.Credentials.Windows.ClientCredential = networkCredential;
ISessionAwareCoreService client = factory.CreateChannel();
Console.WriteLine(client.GetCurrentUser().Title);
}

Resources