I want to integrate xero with c# windows service application.
I did not find a simple code snippet to connect xero with c#. I don't want any user interaction while authorising the user with xero.
I found the code below but it redirects me to xero login page to authenticate and then generates the verification code, how can I avoid this and go ahead because in windows service I will not have any gui to enter verification code.
using System;
using System.Linq;
using System.Windows.Forms;
using Xero.Api.Core;
using Xero.Api.Example.Applications.Public;
using Xero.Api.Example.TokenStores;
using Xero.Api.Infrastructure.OAuth;
using Xero.Api.Serialization;
namespace XeroIntegrationTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ConnectXero();
}
public void ConnectXero()
{
try
{
// Public Application Sample
var user = new ApiUser { Name = Environment.MachineName };
string consumerKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string consumerSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var public_app_api = new XeroCoreApi("https://api.xero.com/api.xro/2.0/", new PublicAuthenticator("https://api.xero.com/api.xro/2.0/", "https://api.xero.com/oauth/RequestToken", "oob",
new MemoryTokenStore()),
new Consumer(consumerKey, consumerSecret), user,
new DefaultMapper(), new DefaultMapper());
var public_contacts = public_app_api.Contacts.Find().ToList();
} catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.StackTrace);
}
}
}
}
But it generates
oauth_problem=permission_denied&oauth_problem_advice=The%20consumer%20was%20denied%20access%20to%20this%20resource
error.
Hope someone will help me.
You need to integrate with "privateKeyAuthendicator" method.
To do this :
1.Create Private/Public Key using below link
https://developer.xero.com/documentation/api-guides/create-publicprivate-key
2.Create ConsumerKey and ConsumerSecret
3.Include Key file into your project folder
4.Use below code snippet to access Xero
var private_app_api = new XeroCoreApi(_xeroSettings.Value.Url, new PrivateAuthenticator(privatekeyFilePath, privatekeypassword),
new Consumer(consumerKey,consumerSecret), null,
new DefaultMapper(), new DefaultMapper());
You need to integrate using the "PrivateAuthenticator" method. The method you are using is the public one and uses a different authentication process which is not suitable for a windows service.
To do this:
Visit the Xero developer portal
Go to the "My Apps" section
Select "Add Application"
Select "Private" from the radio button options (this is important)
Generate a Private/Public key combination (google how to do this)
Follow the code samples in the readme for setting up a connection using the PrivateAuthenticator method
Related
I have been trying WITH NO LUCK, to get an embed token to be able to embed my powerbi reports into my existing .netcore web api application. The front end looks like a super easy 1 simple react component that power bi has prepared for me.
But for the backend, I'm literally going in circles.
I got to the point where I decided the cleanest way for me to do this would be through an HTTP Trigger function.
(see this: https://www.taygan.co/blog/2018/05/14/embedded-analytics-with-power-bi )
As an important side note: I DID already grant my application the necessary delegate READ permissions to the power bi Apis)
Another side note, is that I am attempting to do the master user, app owns data approach
Another side note, is that you will see that my link above, the code shows you to get an AAD auth token using a method that is no longer supported (seemingly) by microsoft, so I changed that line of code as you'll see below
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.Rest;
using Newtonsoft.Json;
namespace PowerBiExample
{
public class EmbedContent
{
public string EmbedToken { get; set; }
public string EmbedUrl { get; set; }
public string ReportId { get; set; }
}
public static class Test
{
private static string tenantId = "this is the id of my entire organization";
static string authorityUrl = $"https://login.microsoftonline.com/{tenantId}";
static string resourceUrl = "https://analysis.windows.net/powerbi/api";
static string apiUrl = "https://api.powerbi.com/";
private static string clientId = "this is the client id of my application that i gave delegate permissions to";
private static string clientSecret = "this is the secret of the application i gave delegate permissions to";
private static string username = "ad master user that i WANTED to sign into power bi with";
private static string password = "that ad users pw";
private static Guid groupId = Guid.Parse("workspaceid in powerbi");
private static Guid reportId = Guid.Parse("report id from within that workspace");
[FunctionName("Test")]
public static async Task<IActionResult> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
{
var credential = new ClientCredential(clientId, clientSecret);
var authenticationContext = new AuthenticationContext(authorityUrl);
// var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientId, credential);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, credential);
string accessToken = authenticationResult.AccessToken;
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(apiUrl), tokenCredentials))
{
// Embed URL
Report report = client.Reports.GetReportInGroup(groupId, reportId);
string embedUrl = report.EmbedUrl;
// Embed Token
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
EmbedToken embedToken = client.Reports.GenerateTokenInGroup(groupId, reportId, generateTokenRequestParameters);
// JSON Response
EmbedContent data = new EmbedContent();
data.EmbedToken = embedToken.Token;
data.EmbedUrl = embedUrl;
data.ReportId = reportId.ToString();
var s = JsonConvert.SerializeObject(data);
return new JsonResult(s);
// JavaScriptSerializer js = new JavaScriptSerializer();
// string jsonp = "callback(" + js.Serialize(data) + ");";
//
// // Return Response
// return new HttpResponseMessage(HttpStatusCode.OK)
// {
// Content = new StringContent(jsonp, Encoding.UTF8, "application/json")
// };
}
}
}
}
I DO get the Authorization Token returned. I DO NOT get the Embed Token returned. I get unauthorized for that.
Also important note: 1. I also didn't enable Service Principal like it says to do here learn.microsoft.com/en-us/power-bi/enterprise/… (my IT dept said I can't). and 2. they are not an admin or member on the workspace but when I try to add them as member, they are not available. It's an Application, not a user or a group. What should I do
Please check if below points can give an idea to work around.
A fiddler trace may be required to investigate further. The required
permission scope may be missing for the registered application
within Azure AD. Verify the required scope is present within the
app registration for Azure AD within the Azure portal ex: openid ,
profile, offline etc depending on the requirement and the user
logged in.
When using a master user, you'll need to define your app's delegated
permissions ( known as scopes). The master user or Power BI
admin is required to grant consent for using these permissions using
the Power BI REST APIs.
For master users, it is essential to grant permissions from the
Azure portal.
Also check if the group Id provided is correct,
Also For Analysis Services, the master user has to be a
gateway admin.
Your web app uses a user account to authenticate against Azure AD
and get the Azure AD token. The master user needs to have a Power
BI Pro or a Premium Per User (PPU) license.
After successful authentication against Azure AD, your web app will
generate an embed token to allow its users to access specific
Power BI content.
Please go through this considerations to generate embed token
carefully and give proper permissions.
Note: For security reasons, the lifetime of the embed token is set to the remaining lifetime of the Azure AD token used to call the
GenerateToken API.
Therefore, if you use the same Azure AD token to generate several embed tokens, the lifetime of the generated embed tokens will be shorter with each call.
Sometimes that can be the reason for the unauthorized error due to expiry of embed token
Please check this powerbi-docs/embedded-troubleshoot.md at live ·
MicrosoftDocs/powerbi-docs · GitHub to see several issues and
find what is the main issue in your case.
And also check if you need to provide datasetId
Some references:
Unauthorized response on GetReportInGroupAsync PowerBI Embedded
API call using Service Principal - Stack Overflow
Register an app to embed Power BI content in a Power BI embedded
analytics application - Power BI | Microsoft Docs
Understand the permission tokens needed for embedding a Power BI
application - Power BI | Microsoft Docs
We used to be able to log into SharePoint Online using the SharePointOnlineCredentials class eg here.
This class is not available in .NET5 and I don't have the necessary Azure permissions to configure the application in Azure AD as described here
I'd like a C# program bring up a prompt, so the user can log into Sharepoint manually. Once the user has done this the program will do what it needs to do. Is there some C# code that will bring up the Sharepoint online login prompt?
I've downloaded Pnp and CSOM. This code contains the following errors.
The name 'GetSecureString' does not exist in the current context
No overload for method 'GetContext' takes 3 arguments
'Program.GetContext(Uri, string, SecureString)': not all code paths return a value
The name 'context' does not exist in the current context
using System;
using System.Security;
using Microsoft.SharePoint.Client;
using System.Threading.Tasks;
using PnP.Framework;
namespace ConsoleApplication1
{
class Program
{
public static async Task Main(string[] args)
{
Uri site = new Uri("https://contoso.sharepoint.com/sites/siteA");
string user = "joe.doe#contoso.onmicrosoft.com";
SecureString password = GetSecureString($"Password for {user}");
// Note: The PnP Sites Core AuthenticationManager class also supports this
using (var authenticationManager = new AuthenticationManager())
using (var context = authenticationManager.GetContext(site, user, password))
{
context.Load(context.Web, p => p.Title);
await context.ExecuteQueryAsync();
Console.WriteLine($"Title: {context.Web.Title}");
}
}
public ClientContext GetContext(Uri web, string userPrincipalName,
SecureString userPassword)
{
context.ExecutingWebRequest += (sender, e) =>
{
// Get an access token using your preferred approach
string accessToken = MyCodeToGetAnAccessToken(new Uri($"
{web.Scheme}://{web.DnsSafeHost}"), userPrincipalName, new
System.Net.NetworkCredential(string.Empty, userPassword).Password);
// Insert the access token in the request
e.WebRequestExecutor.RequestHeaders["Authorization"] =
"Bearer " + accessToken;
};
}
}
}
I'm doing it in MVC (C#). I want to access users google calendar so i have specified a button with "Access Calendar". When a user clicks on the button below code is called to get tokens (and save) for accessing calendar data.
UserCredential credential;
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "xxxxxx.apps.googleusercontent.com",
ClientSecret = "FxxxxxxxxxZ"
},
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath)).Result;
When this method is executed we should be redirected to consent screen, instead, I'm getting the error as
but the redirect URI it is showing I have never specified in the console. These are the redirect uri I have specified in google project console.
Is anything I'm doing wrong? How to get properly redirected to permissions screen ?
Redirect uri issue
The redirect uri in your request is http://127.0.1:59693/authorize you have not added that under Authorized redirect Uris.
You cant just add any redirect uri. The client library builds this url itself. its always
host:port/authorize
Application type
there are several types of clients that you can create these clients are designed to work with different types of applications. The code used to connect with these clients is also different.
installed application - application installed on a users machine
web application - application hosted in a web server connected to a user via a web browser.
Installed Application
You are using GoogleWebAuthorizationBroker.AuthorizeAsync it is designed for use with installed applications. The browser window will open on the machine itself. If you try to host this on a web-server the browser will attempt to open on the server and not be displayed to the user.
Web applications
you should be following Web applications and using GoogleAuthorizationCodeFlow
using System;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Drive.v2;
using Google.Apis.Util.Store;
namespace Google.Apis.Sample.MVC4
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "PUT_CLIENT_ID_HERE",
ClientSecret = "PUT_CLIENT_SECRET_HERE"
},
Scopes = new[] { DriveService.Scope.Drive },
DataStore = new FileDataStore("Drive.Api.Auth.Store")
});
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
}
I have the following code which returns the reports from my SSRS server, afterwards I then store the paths to each individual list which allows users to run them from within the application. The below works fine.
NetworkCredential serviceCredentials = new NetworkCredential()
{
UserName = username,
SecurePassword = EncryptionManager.DecryptToSecureString(password),
Domain = domain
};
reports = new ObservableCollection<object>(reportsManager.FindReports(reportsWebService, reportsFolderName, serviceCredentials));
//FindReports
ReportingService2005 rs = new ReportingService2005();
rs.Url = reportsWebService;
rs.Credentials = serviceCredentials;
CatalogItem[] catalogItems = rs.ListChildren(#"/" + reportsFolderName, false);
However the problem is when a user selects a report to view it shows the following error:
The permissions granted to user are insufficient for performing this
operation.
I understand that the quick fix to this would be to add the users domain into the security section on the Report server, however this is not appropriate.
My question is I can supply credentials to allows a specified user to access the report folder is it possible to pass this along so that user can run a report?
Each of my reports use built in connection strings NOT windows authentication.
Edit: I am using Reporting WinForms.
Windows Forms
In a windows forms project you can pass a suitable System.Net.NetworkCredential to ServerReport.ReportServerCredentials.NetworkCredentials property of ReportViewer. This way, all reports will be executed using the passed credential:
reportViewer1.ServerReport.ReportServerCredentials.NetworkCredentials =
new System.Net.NetworkCredential("username", "password", "domain");
Web Forms
The solution for a Web Forms is different. In a Web Forms project, to pass a suitable credential to RePortViewer you need to implement IReportServerCredentials. Then you can assign the value to ServerReport.ReportServerCredentials property of ReportViewer control. This way, all reports will be executed using the passed credential.
Example
Here is a simple implementation. It's better to store username, password and domain name in app config and read them from config file:
using System;
using System.Net;
using System.Security.Principal;
using Microsoft.Reporting.WebForms;
[Serializable]
public sealed class MyReportServerCredentials : IReportServerCredentials
{
public WindowsIdentity ImpersonationUser { get { return null; } }
public ICredentials NetworkCredentials
{
get
{
return new NetworkCredential("username", "password", "domain");
}
}
public bool GetFormsCredentials(out Cookie authCookie, out string userName,
out string password, out string authority)
{
authCookie = null;
userName = password = authority = null;
return false;
}
}
Then in Page_Load pass the credential this way:
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
this.ReportViewer1.ServerReport.ReportServerCredentials =
new Sample.MyReportServerCredentials();
}
Note
In cases which you want to use ReportViewer with no session state you can also implement IReportServerConnection. In this case you need to add a key value in appsettings section of config file to introduce the implementation this way:
<add key="ReportViewerServerConnection" value="YourNameSpace.YourClass, YourAssemply" />
In this case, you don't need code in Page_Load and the config would be enough. For more information take a look at this great blog post by Brian Hartman.
So I've been trying to fetch a web page that uses authentication to a string and save it to a file. It should be pretty basic so I hope someone can see my errors. I'm very new to C# so treat me thereafter :)
This code functions to some extend, but the file I get is the html for the login screen and not the page that its shown for users that is logged in. What is it I'm doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
namespace fetchingweb
{
class WebAutheticator
{
static void Main(string[] args)
{
string htmlHer = GetWeb();
StreamWriter file = new
StreamWriter("C:\\Users\\user\\Documents\\atextfile.txt");
file.Write(htmlHer);
file.Close();
} //main end
private static string GetWeb()
{
WebClient wc = new WebClient();
wc.Credentials = new NetworkCredential("user", "pass");
string url = "http://someurl.com/index.php";
try
{
using (Stream stream = wc.OpenRead(new Uri(url)))
{
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
catch (WebException e)
{
return "failure!";
}
} //getweb end
} //class end
} //namespace end
You are using NetworkCredential to login at the webapp, but the webapp is using some kind of forms authentication.
As long as the webapp is not configured to use network credentials this will not work.
Since this is a php application I guess it uses plain forms auth and that you will need to post username/password to the login page before continuing.
Look at the code on the login page of the site you're trying to log into and download.
There will be a <FORM..> section, if its post you need to post, if its get you use get. It will either post to a new page, and possibly use redirection, or, even refer to itself. Chances are it will use either some form of session id, or cookies to prove you logged in.
Best way to understand this is to write a proxy, which takes your requests, and shows what you send and what you get back.. As this is the best way to understand what happens when you use things and what your program would need to do to mimic it