Why Does my Service Account Attempt to Connect to Google API via OAuth2 Return an 'invalid_grant' error? - vb.net

I am attempting to use a Service Account to talk to the Admin SDK Directory API via the .Net Client Library. However, the response I keep getting is a 400 Bad Request with a json response content of "error":"invalid_grant".
Here is my code
Public Sub New()
Dim _certificate = New X509Certificate2("c:\path\to\file.psk", "notasecret" _
, X509KeyStorageFlags.Exportable)
Dim _serviceAccountEmail = "email#developer.gserviceaccount.com"
Dim _scopes As IList(Of String) = New List(Of String)()
_scopes.Add(directory_v1.DirectoryService.Scope.AdminDirectoryUserReadonly)
Dim credential = New ServiceAccountCredential(New
ServiceAccountCredential.Initializer(_serviceAccountEmail) With {
.Scopes = _scopes}.FromCertificate(_certificate))
Dim service = New directory_v1.DirectoryService(New BaseClientService.Initializer() With { _
.HttpClientInitializer = credential,
.ApplicationName = "AeriesConnect"})
Dim request = service.Users.List()
request.Domain = "my.domain.com"
Dim users As directory_v1.Data.Users = request.Execute()
For Each user In users.UsersValue
System.Diagnostics.Debug.WriteLine("userName ID: " & user.Id)
Next
End Sub
Service Object
My service object has the following properties. All other properties are empty collections of the UsersResource or GroupsResource
service.BaseUri = 'https://www.googleapis.com/admin/directory/v1"
service.HttpClientInitializer Properties
Notice that the Token property is empty. Does that matter? It seems like it does. Is that my fault?
Request Object
I get the error right at the Execute and the exception is from Google and is a Google.Apis.Auth.OAuth2.Responses.TokenResponseException.
I think I've granted all the permissions I need to BUT keep in mind, this is for a Google Apps for Education account.
Logging in as a Super User to the Developer Console, I've created a project and enabled the Admin SDK API. I've also created the Credentials.
As a 'Super User' in that GAFE, I've gone to the "Security --> Advanced Settings --> Manage API Client Access" area and added my Client ID (not email) and the scope as https://www.googleapis.com/auth/admin.directory.user
Request Header
My request header that is POST to https://accounts.google.com/o/oauth2/token has this
assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6Imh0dHBzOi8vd3d3L
mdvb2dsZWFwaXMuY29tL2F1dGgvYWRtaW4uZGlyZWN0b3J5LnVzZXIiLCJpc3MiOiI2OTY3MTQyNzg2OS1hb
XFmMjVzY204Y2N1azhycHJrMDQ2djAzb2cybGducEBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSAiLC
JhdWQiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvdG9rZW4iLCJleHAiOjE0MTQ2MTY
3NDMsImlhdCI6MTQxNDYxMzE0M30.T9H-3tgOQSNdSj3MrUjJNNR5YqsxuJ97bCMJrrEJQ1Noewyv2mj
Dp96AZSZmzSxseAWrgptUv7sR4Mi21CWNACmjQjWPw8BI48sAyIclUPq6UhtMhRZDB1xX7t-Tq8NSbddJt
yJWxTc-IEAT7ixVpjjrosdG8Zcs0MgTuUgKHb8
&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
...and the last bits of it feel wrong. Why does it feel like it suddenly has been HTML encoded?
Question
What have I done wrong? I'm assuming it think's I'm not authenticated. But what do I need to do differently? I've used their examples to help, but I can't quite figure it out.

My problem was that I had the wrong value in the Service Account Email field. Simple solution. Took me two days to figure it out. Ugh!

Related

Use RestSharp to get MS Graph token

I am new to using MS Graph and the new version of RestSharp. I put together a simple console app in VB.NET to learn the process. Have spent way too much time looking at solutions on the internet, but not getting the answers I want. The ultimate goal is to upload files to a OneDrive account autonomously.
So I created an App registration on Azure for this app. Then to test I created a console app to test how the process works. I am using the latest version of RestSharp which is very different from the version I was using. The console app calls a simple subroutine shown below to get the token to make calls to Graph. When I run I get the errors: "System.Net.ProtocolViolationException' in System.dll" and "System.Net.ProtocolViolationException' in mscorlib.dll". Code follows:
Dim client As New RestClient("https://login.microsoftonline.com/f8cde-----/oauth2/v2.0/token")
Dim request As New RestRequest(Method.Post)
request.AddHeader("Content-Type", "application/x-www-form-urlencoded")
request.AddHeader("Host", "login.microsoftonline.com")
Dim body As String = "client_id=8e4---------" &
"scope=api://8e4da056-8425-4-.default" &
"client_secret=Piy7Q~7----------" &
"grant_type=client_credentials"
request.AddBody(body)
Dim response As RestSharp.RestResponse = Await client.ExecuteAsync(request)
Console.Write(response.Content.ToString)
Console.ReadKey()
End Sub
I admit I really don't know what I am doing here, but want to learn.
I can suggest spending time reading the documentation. RestSharp forms the request correctly if you use the RestRequest API to build the request.
Here is what you need to do:
Dim options = New RestClientOptions("https://login.microsoftonline.com/f8cde-----/oauth2/v2.0/token")
options.BaseHost = "login.microsoftonline.com"
Dim client = New RestClient(options)
Dim request As New RestRequest(Method.Post)
request.AddParameter("client_id", "8e4---------")
request.AddParameter("client_secret", "Piy7Q~7----------")
request.AddParameter("grant_type", "client_credentials")
Dim response = Await client.ExecuteAsync(request)

How to login to Google Calendar without OAuth2?

SUMMARY
I have a Vb.net application (Windows form) and I need to manage google calendar for any of software user. I thought of having the user access directly from the program and not authenticate himself for every operation on the calendar
I tried OAuth2 method but is not user friendly. I must login directly from the app and without json files.
WHAT I TRIED
I'm developing software with integrated Google Calendar.
I'm not a Google API expert, so by searching a bit on the web, I managed to authenticate using the credentials.json file that directly creates Google.
At the moment, the software works like this: I press the "Login" button; automatically opens the Google login page in the browser; I enter email and password on the official Google login page; I access; I manually close the browser page; I go back to the program where a msgbox warns me of successful authentication.
Public scopes As IList(Of String) = New List(Of String)()
Public service As CalendarService
Function LoginGoogle()
scopes.Add(CalendarService.Scope.Calendar)
Dim credential As UserCredential
If Directory.Exists("C:\credentials") Then
Try
Directory.Delete("c:\credentials", True)
Catch
MsgBox("Error! Can't delete folder 'credentials'")
End Try
Using stream As New FileStream("credentials.json", FileMode.Open, FileAccess.Read)
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets, scopes, "user", CancellationToken.None,
New FileDataStore("c:\credentials")).Result
End Using
Dim initializer As New BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = "Carpedia" ' app's name
service = New CalendarService(initializer)
Return 0
Else
Using stream As New FileStream("credentials.json", FileMode.Open, FileAccess.Read)
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets, scopes, "user", CancellationToken.None,
New FileDataStore("c:\credentials")).Result
End Using
Dim initializer As New BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = "Carpedia" ' app's name
service = New CalendarService(initializer)
Return 0
End If
End Function
WHAT I WOULD LIKE
I would like to create a form where to enter email and password; click on the login button; log in automatically without using the browser.
Example: https://youtu.be/FW9_gCD8vVg?t=15 (minute 0:18)
How can I do?
Thanks in advance.
Logging in with username and password though your application is called client login. This was shut down by google in 2015.
In order to access user data you must have the permission of the user to do this. The only way for you to get the permission of the user is to use OAuth2. There is no other option for you to do this. As you can see the google calendar api documentation mentions only oauth2 for accessing private user data.
You appear to already be using the Google APIs .net client library which is the best way i know of to authenticate a user in a windows application.

Dotnetnuke OAUTH/OWIN external Login with facebook

I developed a module for Dotnetnuke(8) with WebAPI 2 Endpoints via the DNN API
This API is consumed by an Android-App.
To access the functions that are populated via the API, the user needs to authenticate.
I have already implemented the JWT (Json Web Token) Authentication with the WebAPI and login with username/password from the App works fine with this method.
Now I also want to allow users to login via their facebook-login and to get their name and email and photo from their facebook profile to authenticate and authorize them via the DNN-Users-Database and allow/disallow them to use the API functions.
I googled around a lot and read a lot of blogposts and articles about external authentication in the last few days. The following are very interesting and already gave me ann good insight how the process may work:
http://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-angularjs-app/
Registering Web API 2 external logins from multiple API clients with OWIN Identity
https://www.asp.net/web-api/overview/security/external-authentication-services
but I cannot really find out (and it seems i do not really understand) if and how this can be made working with my dnn-API and the JSON-WebToken Auth Method in my project.
If anybody can help to get me in the right direction, your help is highly appreciated.
Thanks in advance and kind regards
Don
EDIT: The DNN-API gives all the JWT-Functionality I just need to define the api paths and functions. e.g:
'
<Route("{controller}/{action}/{p1}")>
<AcceptVerbs("GET")>
<AllowAnonymous>
Public Function userInf(ByVal p1 As String) As HttpResponseMessage
Dim response As New HttpResponseMessage
Dim pID As Integer = DotNetNuke.Entities.Portals.PortalController.Instance.GetCurrentPortalSettings.PortalId
Dim objUserInfo As New DotNetNuke.Entities.Users.UserInfo
objUserInfo = DotNetNuke.Entities.Users.UserController.Instance.GetUserById(pID, CInt(p1))
If Not objUserInfo Is Nothing Then
If objUserInfo.UserID > 0 Then
response = Request.CreateResponse(System.Net.HttpStatusCode.OK, JsonConvert.SerializeObject("Username: " & objUserInfo.Username.ToString))
Else
' Not logged in
response = Request.CreateResponse(System.Net.HttpStatusCode.Unauthorized, "Not found")
End If
Else
' Not logged in
response = Request.CreateResponse(System.Net.HttpStatusCode.Unauthorized, "Not logged in")
End If
response.Headers.Add("Access-Control-Allow-Origin", CORS) ' <- Allow CORs !!!!
' response.Headers.Add("Access-Control-Request-Method", "*")
Return response
End Function
The Api Path for the DNN Web-API is for authentication:
example.com/DesktopModules/JwtAuth/API/mobile/Login
where I pass the username and password in the request-body as a json-object
(Documentation on dnnsoftware[dot]com / docs / administrators / jwt /)
This all works as expected. The thing now is how to make work the facebook login as an external login work together with my JWT-AUTH
Web api doing authentication by itself, yout need to create OAuthAuthorizationServerOptions and configure web api to use methods, there is an example of how web api token based auth works with standart Bearer token.
There ApplicationOAuthProvider its a class which generates token for inhereting from OAuthAuthorizationServerProvider.
To call method from your token generator you need to get to the path /api/token and request will automaticly give you token and user Claims, which you will define in your token generator.
public void ConfigureOAuth(IAppBuilder app)
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
var oauthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(24),
Provider = new ApplicationOAuthProvider(),
};
// Token Generation
app.UseOAuthAuthorizationServer(oauthServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
Hope this help.

Reporting Services Authentication issue

I am trying to programmatically render a PDF using Azure Reporting Services. I suspect that the actual PDF retrieval is fine, but I cannot find a way to authenticate the connection before requesting the report (via URL). I am working in the services layer of my web application and I cannot use a web reference (might not work with Azure) and it doesn't make sense to use a ReportViewer control (since it's a service layer method).
I have all the details to connect, but I suspect that I require a cookie to authenticate and I'm not sure how to manually create this. Any suggestions/solutions?
Here's my code so far:
string userName = BJConfigurationManager.GetSetting("ReportingServiceUsername");
string password = BJConfigurationManager.GetSetting("ReportingServicePassword");
NetworkCredential networkCredential = new NetworkCredential(userName, password);
Domain.Report report = GetReportById(id);
int timeout = 30; //seconds
string url = "https://bleh.ctp.reporting.database.windows.net/ReportServer/Pages/ReportViewer.aspx?...";
string destinationFileName = "#C:\\Temp.pdf";
// Create a web request to the URL
HttpWebRequest MyRequest = (HttpWebRequest)WebRequest.Create(url);
MyRequest.PreAuthenticate = true;
MyRequest.Credentials = networkCredential;
MyRequest.Timeout = timeout * 1000;
try
{
// Get the web response -- THE RESPONSE COMES BACK AS UNAUTHENTICATED...
HttpWebResponse MyResponse = (HttpWebResponse)MyRequest.GetResponse();
Check out the section titled "SOAP Management Endpoint Programmatic Access":
http://msdn.microsoft.com/en-us/library/windowsazure/771e88b6-ab0f-4910-a5fa-5facd8d56767#SOAPManagement.
It explains how to authenticate using a cookie container without a ReportViewer control.
I don't think that is going to work. Azure Reporting uses Forms Authentication and as I understand it, you aren't going to be able to match the Forms Auth cookie along with the MachineKey for encryption.
I was trying to accomplish the same task..but using a WebRequest was impossible.
I changed the approach using a ServerReport class like this:
ServerReport report;
report = new ServerReport();
report.ReportServerUrl = new Uri(reportServerName + "/ReportServer");
report.ReportPath = "/ReportPath";
report.ReportServerCredentials = new ReportServerCredentials();
report.SetParameters(new Microsoft.Reporting.WebForms.ReportParameter("param1", param1));
report.SetParameters(new Microsoft.Reporting.WebForms.ReportParameter("param2", param1));
return report.Render(reportParams.OutputFormat);
The ReportServerCredentials class must implement the IReportServerCredentials interface like this.
More info about the IReportServerCredentials interface and implementation here.

Calling SharePoint Web Service over SSL in VB.Net (401 Unauthorized)

I'm trying to call the AddAttachment of the Lists.asmx SharePoint web service the below code works fine if I'm calling the web service over HTTP.
Dim img(MyFile.PostedFile.ContentLength - 1) As Byte
MyFile.PostedFile.InputStream.Read(img, 0, img.Length)
'Dim fStream As FileStream = File.OpenRead(FullFileName)
Dim fileName As String = MyFile.PostedFile.FileName.Substring(3)
Dim listService As New wsList.Lists()
Dim credentials As New System.Net.NetworkCredential(UserName, Password, Domain)
If Not SiteUrl.EndsWith("/") Then
SiteUrl += "/"
End If
SiteUrl += "_vti_bin/Lists.asmx"
'SiteUrl = SiteUrl.ToLower.Replace("http:", "https:")
listService.Url = SiteUrl
listService.Credentials = credentials
Dim addAttach As String = listService.AddAttachment(ListName, ItemId, fileName, img)
ReturnValue = True
However if I uncomment out this line
'SiteUrl = SiteUrl.ToLower.Replace("http:", "https:")
I will get the following error: The request failed with HTTP status 401: Unauthorized
Now if I leave the above line commented out AND then also comment out this line
listService.Credentials = credentials
I will get the same 401 error (expected) so it appears the credentials are being accepted correctly over HTTP but not HTTPS. Can one help explain this to me and have any thoughts on how to fix the issue?
Thanks in advance!
This morning I was working with one of our system guys. He checked some IIS logs and could see errors trying to access the web service over HTTPS. He went into Central Admin and added some Alternate Access Mappings to include the HTTPS urls. Then everything worked!