DotNetOpenAuth - A property with the name 'OriginalHttpRequestUri' is not present Exception - c#

I am attempting to implement the example from the DotNetOpenAuth Service Provider solution but instead of using OpenId for authentication, I am using Forms Authentication.
I copied and pasted the Consumer example but removed the Service Reference and added a new service reference pointing to my WCF service.
Getting of the Access Tokens is working great and I can see them appearing in my database table, however, as soon as I attempt to access data, it is failing on this line in the OAuthAuthorizationManager class:
Uri requestUri = OperationContext.Current.IncomingMessageProperties["OriginalHttpRequestUri"] as Uri;
Is there something I am missing somewhere? It seems that this property should exist because I don't see where it is manually added anywhere in the original. I copied and pasted the Web.config from the sample Service Provider project and all of my files are named the same.
Let me know if there is any more information needed or if anyone wants me to email them the sample project to look at.
Thanks for any assistance.

Uri requestUri = operationContext.RequestContext.RequestMessage.Properties.Via;
I think it is a more secure way of finding the original HTTP information.

Related

ASP.NET Core 2.1 get current web hostname and port in Startup.cs

I want to register my WebAPI to Consul service discovery and for that I should provide URL of my WebAPI (for example: http://service1.com) and health check endpoint (http://service1.com/health/check). How can I get that URL?
I found this piece of code:
var features = app.Properties["server.Features"] as FeatureCollection;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.First();
var uri = new Uri(address);
It returns 127.0.0.1:16478 instead of localhost:5600. I think first one used by dotnet.exe and second one is IIS which forwards 5600 to 16478. How can I get localhost:5600 in Startup.cs?
Well, there are multiple solutions for this problem. Your address is this:
string myurl = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}";
It returns 127.0.0.1:16478 instead of localhost:5600
You got this right yes. One is from IIS and one from dotnet. So, you have a problem of trying to get correct url. Ok, so what happens if you service is behind reverse proxy? https://en.wikipedia.org/wiki/Reverse_proxy
Then your service will not be exposed directly to internet, but requests made to specific url will be passed from reverse proxy to your service. Also, you can configure reverse proxy to forward additional headers that are specifying where the original request came from. I think that most reverse proxies are using X-Forwarded-For (Some of them are using X-Original-Host etc).
So if you have proper header set on RP, then you can get url like this:
url = url.RequestContext.HttpContext.Request.Headers["X-Forwarded-For"]
Url is of type UrlHelper. To simplify this method, you can create extension method (GetHostname(this UrlHelper url)) and then us it in your controller or wherever you want. Hope it helps
I don't think it is possible since there is usually a reverse proxy in production that handles public address and the application itself should not be exposed to public and, therefore, be aware of public address. But there can be some workarounds:
Place URL is some kind of config file that can be updated during deploy steps to have the correct URL.
Application can get full URL of the request like this, so after first actual request to the application we can get hostname.
EDIT: I reread your question. You wanted to know how to do this in Startup.cs. You can, but with fewer fallbacks. Your only choices are configuration or raw DNS.GetHostName(), which are less than ideal. Instead, upon any request to your service, lazily register your API. This is when you have context. Prior to that, your service knows nothing Jon Snow. The first request to your API is likely going to be health-checks, so that will kick off your registration with consul.
A solution I've used is a combination of configuration and headers in a fallback scenario.
Rely first on the X-Forwarded-For header. If there are cases where that doesn't apply or you have a need to... you can fallback to configuration.
This works for your use case, discovery. That said, it also works when you want to generate links for any reason, (e.g. for hypermedia for JSON API or your own REST implementation).
The fallback can be useful when there are reconfigurations occuring, and you have a dynamic configuration source that doesn't require a redeployment.
In the ASP.NET Core world, you can create a class and inject it into your controllers and services. This class would have a method that knows to try config first (to see if overriding is needed) and then the X-Forwarded-For header, and if neither is appropriate, fallback further to HttpContext.Request to get relevant URI parts.
What you're doing is enabling your API to be contextless and resiliency (to change) by giving it some contextual awareness of where "it lives".
This happens when you try to get current URL in Startup.cs. I've faced this issue before. What i did as Solution for my problem is. I Just declared Custom Setting in AppSettings in web.config(For Local) file and web.release.config(For Live)
like following
in web.config
<appSettings>
<add key="MyHost" value="http://localhost:5600" />
</appSettings>
in web.release.config
<appSettings>
<add key="MyHost" value="http://myLiveURL.com" />
</appSettings>
in startup.cs
string hostSetting = ConfigurationSettings.AppSettings["MyHost"];
And different host in release file. so what it helped is i can get Localhost URL in local website from web.config and Live URL from web.release.config.
if you are using Azure for live. it will be more easier for live(you would not need to add setting web.release.config file). add app setting in your website application setting https://learn.microsoft.com/en-us/azure/app-service/configure-common
In Case of ASP.NET Core you can use appsettings.json instead of web.config

How to work with Visual Studio 2017 generated restful api from swagger docs

So I am working with Visual Studio 2017 Enterprise, and I noticed the other day that you can right click and do file add restful api client. So I went out and generated the .json file for my restful service. My Visual Studio generated a bunch of classes and files. However, I don't understand how to work with these classes?
What is an example code of creating an object to call my restful backend methods?
I thought perhaps this was the object I need to work with, but then what are the ServiceClientCredentials if they cannot be null?
public AngularDemoComplete(ServiceClientCredentials credentials, params DelegatingHandler[] handlers) : this(handlers)
{
if (credentials == null)
{
throw new ArgumentNullException("credentials");
}
this.Credentials = credentials;
if (this.Credentials != null)
{
this.Credentials.InitializeServiceClient(this);
}
}
I am still trying to work out a complete solution, but I did manage to get this working by passing in these parameters:
(new TokenCredentials("<bearer token>"), null)
Unfortunately I don't really understand what this means at the moment. I found this in a post about working with autorest clients, which seems to generate similar code: https://dzimchuk.net/generating-clients-for-your-apis-with-autorest/
I am continuing to work this out and will update this as I learn more.
Any updates from you would be appreciated.
Cheers
Additionally, I got it working by commenting out the null check on the credentials parameter. But that probably is not advisable. It is just interesting to note that it can work without the credentials if there is no authentication required.
UPDATE: I have found there are 2 other types of credentials available that appear to be a bit more self explanatory:
BasicAuthenticationCredentials
CertificateCredentials
Apparently with the TokenCredentials you would need to obtain the token from the server prior to this step. This might be needed if using OAuth.
As I don't need authentication initially, I am just going to use the BasicAuthenticationCredentials without setting the UserName and Password properties.
I was surprised there were not more examples of how to use the generated code, created by https://github.com/Azure/AutoRest so I thought it worthwhile to add something here.
+10 for #Keiran for referring to BasicAuthenticationCredentials, which as it turns out, extends BasicAuthenticationCredentials and therefore, can be used as follows:
BasicAuthenticationCredentials credentials = new BasicAuthenticationCredentials();
credentials.UserName = "joe#bloggs.com.au";
credentials.Password = "passwordvalue";
System.Uri baseUri = new System.Uri("https://api.something.com.au/v0.1/");
APIClassName client = new APIClassName(baseUri, credentials);
APIClassNameSpace.Models.SomeResponse someResponse = client.GetSomething(requestHeaderParameter1, pathParameter1);
Visual Studio 2019 currently produces a Models folder containing all of the classes referenced by the swagger file. It also produces three other classes, e.g. IAPIClassName, APIClassName, APIClassNameExtensions. Use APIClassName to instantiate the client - the operations specified in the swagger file will be available with auto-completion. I didn't dig too deeply but the class prefixed with I looked like an interface definition and the class suffixed with extensions looked lie the implementation of the interface. My example illustrated the use of a request header parameter and a path parameter although the implementation of that handling is generated using the details in the swagger file.
I must mention How to handle both a single item and an array for the same property using JSON.net as part of this discussion. Anyone dealing with the JSON and generated code for should know about this!

Google Datastore authentication issue - C#

I'm trying to connect to the Google Datastore on my account with service account credentials file (which I've created according to the documentation), but I'm encountering with authentication error while trying to insert an entity:
Grpc.Core.RpcException: Status(StatusCode=Unauthenticated,
Detail="Exception occured in metadata credentials plugin.")
My code is:
var db = DatastoreDb.Create("myprojectid");
Entity entity = new Entity{
Key = db.CreateKeyFactory("mykindname").CreateIncompleteKey()
};
var keys = await db.InsertAsync(new[] { entity });
The GOOGLE_APPLICATION_CREDENTIALS variable refers to the credentials file and when calling GoogleCredential.GetApplicationDefaultAsync() to see if the credentials object is valid it indeed looks good...
I saw some earlier examples which used the GetApplicationDefaultAsync function togehether with some DatastoreService object - but I couldn't find the DatastoreService object (probably it was there in old versions...) in the latest .Net API: Google.Cloud.Datastore.V1
Notice that I don't want to use the other authenticaiton methods:
1) Using the gcloud cli.
2) Running from Google environment (app engine for example).
Any idea how to solve this?
After the great help of Jon Skeet the issue was solved.
The authentication issues can occur if you don't reference all the required Datastore dlls. Make sure that all the dlls are referenced on the project that are running the calls to the Datastore.
I've added the Google Datastore lib via the NuGet to my test project and everything worked!
Notice that in such cases it is recommended to enable gRPC logging. `(For exmaple: GrpcEnvironment.SetLogger(new ConsoleLogger()), there you'll probably see if there were issues loading several dlls...
Authentication can be broken if your system clock is significantly incorrect. Check your system time, and fix it if necessary, then try authenticating against Datastore again.

How to expose simple web service using Basic Authentication in ASP.NET

I maintain an ASP.NET Web API project which supports a simple REST end point for clients to post XML data to our server. This site is setup to support BasicAuthentication and works very well. All of our security checks are done at the network firewall and on the machine itself using custom Windows User accounts. Recently, one of our clients requires that we support a SOAP end point to receive the XML data as well.
My thought was to simply add a new WebService (Blah.svc) with supporting interface having the required [ServiceContract] and [OperationContract] attributes to my interface. I had hoped that I could simply expose the URL to our client and it would "just work". I am able to hit the end point, but this service is not able to extract the user name.
Here is my sample code:
public string CreateWorkItem(string xml)
{
var userName = HttpContext.Current.User.Identity.Name;
if (string.IsNullOrEmpty(userName))
userName = "NO USER NAME";
var elem = XElement.Parse(xml);
return $"Hello [{userName}]! You sent [{elem.Value}].";
}
Here are my results:
I've scoured the web to try and find out how to get access to the BasicAuthentication details in a Soap message, but I'm not having any luck. All the examples that I'm finding require that I create a new WCF project and expose it with a lot of web.config settings, or the examples are ~5 years old using older techniques.
I'd like this service to simply publish with my WebAPI project using the Publish... option inside Visual Studio. Unfortunately, I've not found a common denominator to make it work. I'm sure I'm missing something, and I hope someone can help.
Any help would be greatly appreciated!
Check this link out: WCF Services and ASP.NET
In short you need to enable ASP.NET Compatibility in your WCF service.
However, you may want to look into using OperationContext.Current.ServiceSecurityContext.*
The fact that it is HttpContext.Current.User.Identity.Name is returning null means either:
User is null; or
User is Anonymous
I have a few ideas to help resolve the issue.
1. Your User.Name is actually null
You might want to debug by grabbing HttpContext.Current.User and see if it's correct.
2. Go direct: get the cookie via a parameter
Try and pass the HttpContext as a parameter so you can grab the cookie?
public string CreateWorkItem(HttpContext context, string xml)
{
var username = context.Current.User.Identity.Name;
...
}
3. Your configurations are not setup properly
The alternative is that maybe your web.config or Global.asax is not setup to properly.

Trello C# api, .Boards.WithId() and .Members.Me() are always null [duplicate]

I am new to Trello.Net and struggling a little with authorisation. I understand the process, of requesting a URL and then asking the user to browse to that URL to get a token.
The first problem is I am trying to write a process which runs automatically without any UI. So I'm having to use a hard coded token, which I obtained by running this code to get a URL, which I then browse to manually. I would rather do this part automatically (get the resulting token programatically, not by having the user browse somewhere):
ITrello trello = new Trello(Key);
var url = trello.GetAuthorizationUrl("TrelloCapture", Scope.ReadWrite, Expiration.Never);
Console.WriteLine(url);
This URL, when I browse to it, displays for me a token which, for now, I hardcoded into my application as follows:
var token = "[the token copied and pasted from the web page]"
I then authorise using:
trello.Authorize(token);
Which seems to work fine. Next I want to access some basic data, and this is where my second problem comes in.
// Get the authenticated member
Member me = trello.Members.Me();
Console.WriteLine(me.FullName);
Members.Me() returns null every time. The same problem with Cards.ForMe() and other methods. Everything is null. Why?
What am I doing wrong?
I found the answer. I fixed it by getting the latest versions of these NuGet packages in my solution:
Trello.Net
JSON.Net
RestSharp
After getting those latest versions I was seeing proper values instead of null in the trello objects.
Hope this helps somebody who reads this.
Had the same problem, above answer helped me.
Though I couldn't get the latest but had to use:
"RestSharp" version="104.1
"Newtonsoft.Json" version="6.0.1"
Since The nuget also doesn't have the correct color enum i had to download the project and make my own changes.

Categories