How to use WindowsIdentity.RunImpersonated(handle, action); - .net-core

We are trying to use RunImpersonated(handle, action); to be able to perform a REST call from a webserver but we have a hard time doing so. Project i ASP.NET Core 2.0 MVC.
We have the following general method made to establish a imp. context on behalf of the logged in wnd. user:
var user = WindowsIdentity.GetCurrent();
IntPtr token = user.Token;
SafeAccessTokenHandle handle = new SafeAccessTokenHandle(token);
WindowsIdentity.RunImpersonated(handle, action);
and basically in the action we make our REST call.
Thing is that we CAN run through without any problems running locally on our dev machines but we can't do the same on the remote webserver. Hence: impersonation.
Is our approach above for the imp. part right since we can't actually se if we promote any user-credentials?
We have tried different techniques in the REST-GET impl. as well without the above. On the other hand the above call are made closer to our controller and on REST impl. not having any specifics for imp. itself.

I was concerned with some time ago. As far as I can remmember, this worked for me:
Create an asynchronous action filter:
public class ImpersonationFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
var user = (WindowsIdentity)context.HttpContext.User.Identity;
await WindowsIdentity.RunImpersonated(user.AccessToken, async () =>
{
await next();
});
}
}
Register it as any other filter.

Related

How can I ensure an API call response completes before an operation in Blazor WASM

I've scoured stackoverflow looking for ways to make synchronous API calls in Blazor WASM, and come up empty. The rest is a fairly length explanation of why I think I want to achieve this, but since Blazor WASM runs single-threaded, all of the ways I can find to achieve this are out of scope. If I've missed something or someone spots a better approach, I sincerely appreciate the effort to read through the rest of this...
I'm working on a Blazor WASM application that targets a GraphQL endpoint. Access to the GraphQL endpoint is granted by passing an appropriate Authorization JWT which has to be refreshed at least every 30 minutes from a login API. I'm using a 3rd party GraphQL library (strawberry-shake) which utilizes the singleton pattern to wrap an HttpClient that is used to make all of the calls to the GraphQL endpoint. I can configure the HttpClient using code like this:
builder.Services
.AddFxClient() // strawberry-shake client
.ConfigureHttpClient((sp, client) =>
{
client.BaseAddress =
new Uri(
"https://[application url]/graphql"); // GraphQL endpoint
var token = "[api token]"; // token retrieved from login API
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
});
The trick now is getting the API token from the login API at least every 30 minutes. To accomplish this, I created a service that tracks the age of the token and gets a new token from the login API when necessary. Pared down, the essential bits of the code to get a token look like this:
public async Task<string> GetAccessToken()
{
if ((_expirationDateTime ?? DateTime.Now).AddSeconds(-300) < DateTime.Now)
{
try
{
var jwt = new
{
token =
"[custom JWT for login API validation]"
};
var payload = JsonSerializer.Serialize(jwt);
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var postResponse = await _httpClient.PostAsync("https://[login API url]/login", content);
var responseString = await postResponse.Content.ReadAsStringAsync();
_accessToken = JsonSerializer.Deserialize<AuthenticationResponse>(responseString).access_token;
_expirationDateTime = DateTime.Now.AddSeconds(1800);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
return _accessToken;
}
So, now I need to wire this up to the code which configures the HttpClient used by the GraphQL service. This is where I'm running into trouble. I started with code that looks like this:
// Add login service
builder.Services.AddSingleton<FxAuthClient>();
// Wire up GraphQL client
builder.Services
.AddFxClient()
.ConfigureHttpClient(async (sp, client) =>
{
client.BaseAddress =
new Uri(
"https://[application url]/graphql");
var token = await sp.GetRequiredService<FxAuthClient>().GetAccessToken();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
});
This "works" when the application is loaded [somewhat surprisingly, since notice I'm not "await"ing the GetAccessToken()]. But the behavior if I let the 30 minute timer run out is that the first attempt I make to access the GraphQL endpoint uses the expired token and not the new token. I can see that GetAccessToken() refreshes expired token properly, and is getting called every time I utilize the FxClient, but except for the first usage of FxClient, the GetAccessToken() code actually runs after the GraphQL request. So in essence, it always uses the previous token.
I can't seem to find anyway to ensure that GetAccessToken() happens first, since in Blazor WASM you are confined to a single thread, so all of the normal ways of enforcing synchronous behavior fails, and there isn't an asynchronous way to configure the FxClient's HttpClient.
Can anyone see a way to get this to work? I'm thinking I may need to resort to writing a wrapper around the strawberry FxClient, or perhaps an asynchronous extension method that wraps the ConfigureHttpClient() function, but so far I've tried to avoid this [mostly because I kept feeling like there must be an "easier" way to do this]. I'm wondering if anyone knows away to force synchronous behavior of the call to the login API in Blazor WASM, sees another approach that would work, or can offer any other suggestion?
Lastly, it occurs to me that it might be useful to see a little more detail of the ConfigureHttpClient method. It is autogenerated, so I can't really change it, but here it is:
public static IClientBuilder<T> ConfigureHttpClient<T>(
this IClientBuilder<T> clientBuilder,
Action<IServiceProvider, HttpClient> configureClient,
Action<IHttpClientBuilder>? configureClientBuilder = null)
where T : IStoreAccessor
{
if (clientBuilder == null)
{
throw new ArgumentNullException(nameof(clientBuilder));
}
if (configureClient == null)
{
throw new ArgumentNullException(nameof(configureClient));
}
IHttpClientBuilder builder = clientBuilder.Services
.AddHttpClient(clientBuilder.ClientName, (sp, client) =>
{
client.DefaultRequestHeaders.UserAgent.Add(
new ProductInfoHeaderValue(
new ProductHeaderValue(
_userAgentName,
_userAgentVersion)));
configureClient(sp, client);
});
configureClientBuilder?.Invoke(builder);
return clientBuilder;
}

Add recaptcha to ASP Web API Login (/Token)?

I've successfully added Google's re-captcha v2 to a few of my API controllers and front end app however I'm struggling to find how to do it for the inbuilt Identity Login (or rather, /Token) endpoint.
I was going to put it in ApplicationOAuthProvider under the Task GrantResourceOwnerCredentials however this accepts context.UserName and context.password from OAuthGrantResourceOwnerCredentialsContext. I'm wondering where this is located so I can get it to accept an additional parameter (the g-captcha-response)?
Thanks!
You can use this code.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var formData = context.Request.ReadFormAsync().Result;
var captchaResponse = formData.Get("g-recaptcha-response");
var result= _captchaService.VerifyCaptcha(captchaResponse);
......
}
Form Data Sample

Asychronous Task works with HttpClient object but not with project's class in Web Generic Handler

I found an interesting differences between .NET Framework's HttpClient class/objects and the VS-2013 Project PhotoServer (DLL) class/objects. It made me wonder if there's a bug with the script.
I'm using .NET Framework v4.5.1.
I'm using the HttpClient script in the sychronous Web Generic Handler. Noticed that I'm using the ".Result" for the asynchronous POST to wait for response. So, looking at HttpClient which works is
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(
_baseUrl,
new FormUrlEncodedContent
(
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Vin", parmVin),
new KeyValuePair<string, string>("ImageSize", parmImageSize)
}.ToArray()
)
).Result;
//returned string[] datatype...
var photoUrls = response.Content.ReadAsStringAsync().Result;
}
I'm using the "GetPhotoUrlsAsync" script in the sychronous Web Generic Handler. This "GetPhotoUrlsAsync" object comes from the Project class (DLL). Again, I'm using the ".Result" and it doesn't work, it just deadlocked and hung. What I wanna know is why is that and was there a bug with the script?
//[Scripts in Web Generic Handlers]...
var managerVehiclePhoto = new ManagerVehiclePhoto();
var photoUrls = managerVehiclePhoto.GetPhotoUrlsAsync("12345678901234567").Result;
//[Project Class]...
namespace BIO.Dealer.Integration.PhotoServer
{
public seal class VehiclePhotoManager
{
public async Task<string[]> GetPhotoUrlsAsync(string vin)
{
var listResponse = await _client.ListAsync(vin);
return listResponse.ToArray();
}
}
}
Thanks...
Edit #1
//Synchronous API Call...
public string[] GetPhotoUrls(string vin)
{
return GetPhotoUrlsAsync(vin).Result;
}
Using .Result like this is actually a bug in both cases; it just happens not to deadlock in the HttpClient case. Note that the same HttpClient library on other platforms (notably Windows Phone, IIRC) will deadlock if used like this.
I describe the deadlock in detail on my blog, but the gist of it is this:
There's an ASP.NET "request context" that is captured by default every time you use await. When the async method resumes, it will resume within that context. However, types such as HttpContext are not multithread-safe, so ASP.NET restricts that context to one thread at a time. So if you block a thread by calling .Result, it's blocking a thread inside that context.
The reason GetPhotoUrlsAsync deadlocks is because it's an async method that is attempting to resume inside that context, but there is already a thread blocked in that context. The reason HttpClient happens to work is because GetAsync etc. are not actually async methods (note that this is an implementation detail and you should not depend on this behavior).
The best way to fix this is to replace .Result with await:
var managerVehiclePhoto = new ManagerVehiclePhoto();
var photoUrls = await managerVehiclePhoto.GetPhotoUrlsAsync("12345678901234567");
Me again (re: same quest WebPages async) :) That said, I'm one of those that Stephen Cleary identifies as "trying to migrate into async", so all this is (still) a learning moment.
The issue is SynchronizationContext in GUI/ASP.Net. I won't mangle Stephen's explanation so the link is your best bet to grok.
Given the best practices in that article, here's my way (consequently what I use in WebPages for the "top level call") to "mock" awaiting a PostAsync call like what you're doing. In this case I'm using ConfigureAwait (call is from WebPages, not MVC):
public static async Task<string> PostToRequestBin()
{
var _strContent = new FormUrlEncodedContent(new[] {new KeyValuePair<string,string>("fizz","buzz")});
using (var client = new HttpClient())
{
/*
* See http://requestb.in/ for usage
*/
var result = await client.PostAsync("http://requestb.in/xyzblah", _strContent).ConfigureAwait(false);
return await result.Content.ReadAsStringAsync();
}
}
In my WebPages page:
#{
//Class2 is a mock "library" in App_Code where the above async code lives
var postcatcher = Class2.PostToRequestBin();
}
And to make use of it somewhere in the page (where I make use of Task<string>.Result:
<p>#postcatcher.Result</p>
Again, this is a learning moment and I hope it helps/guides you. I fully expect the SO community to comment and or correct/improve on this like:
"Why don't I have to ConfigureAwait on ReadAsStringAsync" (it works either way)?
because at this point, it's "async all the way". I could have awaited some other async method...
...so the learning moments continue :)

Authorization_code grant flow on Owin.Security.OAuth: returns invalid_grant

I am trying to setup my authentication using the authorization_code grant flow. I had it previously working with grant_type=password, so I kind of know how the stuff is supposed to work. But when using grant_type=authorization_code, I couldn't make it return anything other than invalid_grant
Here is my setup:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/auth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
Provider = new SampleAuthProvider()
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = "Bearer"
});
SampleAuthProvider is the following class: https://gist.github.com/anonymous/8a0079b705423b406c00
Basically, it's just logging every step and validating it. I tried the request:
POST http://localhost:12345/auth/token
grant_type=authorization_code&code=xxxxxx&client_id=xxxxx&redirect_uri=https://xxxx.com/
Content-Type: application/x-www-form-urlencoded
It's going through:
OnMatchEndpoint
OnValidateClientAuthentication
And that's all. I expected it to call OnValidateTokenRequest and OnGrantAuthorizationCodenext, but it just didn't. I have no idea why.
The xxxx's in the request aren't placeholders, I tried it like that. Maybe the middleware makes some checks on its own and rejects the request because of that? I tried variants of the redirect_uri with http, without any protocol, without trailing slash...
It also works properly with a custom grant_type. It so if I too desperate, I guess I can use that to simulate authorization_code, but I'd rather not have to do that.
TL;DR
My OAuthAuthorizationServerProvider returns {"error":"invalid_grant"}after OnValidateClientAuthentication when using grant_type=authorization_code.
Why is it stopping there?
How can I make the whole damn thing work?
Thanks for your help!
Edit
As pointed out by RajeshKannan, I made a mistake in my configuration. I didn't provide an AuthorizationCodeProvider instance. However, that didn't completely solve the problem, since in my case, the code is not issued by the AuthorizationCodeProvider, and I can't just deserialize it. I anwered with the workaround I got working.
Here is what I got working. I'm not completely comfortable with that solution, but it works and should help others to fix their issues.
So, the issue is that I didn't set the AuthorizationCodeProvider property. When a request with grant_type=authorization_code is received, the code must be validated by that code provider. The framework assumes that the code was issued by that code provider, but that's not my case. I get it from another server and have to send the code back to it for validation.
In the standard case, where you are also the one issuing the code, the link provided by RajeshKannan describes everything you have to do.
Here is where you have to set the property:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString(Paths.TokenPath),
Provider = new SampleAuthProvider(),
AuthorizationCodeProvider = new MyAuthorizationCodeProvider ()
}
And the declaration of the MyAuthorizationCodeProvider class:
internal class MyAuthorizationCodeProvider : AuthenticationTokenProvider
{
public override async Task ReceiveAsync(
AuthenticationTokenReceiveContext context)
{
object form;
// Definitely doesn't feel right
context.OwinContext.Environment.TryGetValue(
"Microsoft.Owin.Form#collection", out form);
var redirectUris = (form as FormCollection).GetValues("redirect_uri");
var clientIds = (form as FormCollection).GetValues("client_id");
if (redirectUris != null && clientIds != null)
{
// Queries the external server to validate the token
string username = await MySsoService.GetUserName(context.Token,
redirectUris[0]);
if (!string.IsNullOrEmpty(username))
{
var identity = new ClaimsIdentity(new List<Claim>()
{
// I need the username in GrantAuthorizationCode
new Claim(ClaimTypes.NameIdentifier, username)
}, DefaultAuthenticationTypes.ExternalBearer);
var authProps = new AuthenticationProperties();
// Required. The request is rejected if it's not provided
authProps.Dictionary.Add("client_id", clientIds[0]);
// Required, must be in the future
authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1);
var ticket = new AuthenticationTicket(identity, authProps);
context.SetTicket(ticket);
}
}
}
}
I had the same error. Things I was missing:
Specify OAuthAuthorizationServerOptions.AuthorizationCodeProvider according to the documentation.
Specify the same client_id as a GET-parameter when making a request to the token endpoint as you did when you received the authorization_code.
Override OAuthAuthorizationServerProvider.ValidateClientAuthentication and in this method call context.TryGetFormCredentials. This sets the property context.ClientId to the value from the client_id GET-parameter. This property must be set, otherwise you'll get the invalid_grant error. Also, call context.Validated().
After doing all of the above, I could finally exchange the authorization_code to an access_token at the token endpoint.
Thanks scenario, My code was missing the following two required values. Posted here in case others find it useful:
// Required. The request is rejected if it's not provided
authProps.Dictionary.Add("client_id", clientIds[0]);
// Required, must be in the future
authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1);
Make sure that you have configured your authorization server options.
I think you should provide your authorize end point details:
AuthorizeEndpointPath = new PathString(Paths.AuthorizePath)
In the below link, the authorization code grant will be explained in detail and it lists the method which were involved in authorization code grant life cycle.
Owin Oauth authorization server
The answer by #dgn more or less worked for me. This is just an extension to that. As it turns out, you can supply whatever string you want to the ClaimsIdentity constructor. The following works just as well, and doubles up as a detailed code comment:
var identity = new ClaimsIdentity(
#"Katana - What a shitty framework/implementation.
Unintuitive models and pipeline, pretty much have to do everything, and the docs explain nothing.
Like what can go in here? WTF knows but turns out as long as _something_ is in here,
there is a client_id key in your AuthenticationProperties with the same value as
what's set inside your implementation for OAuthAuthorizationServerProvider.ValidateClientAuthentication, and
your AuthenticationProperties.ExpiresUtc is set to some time in the future, it works.
Oh and you don't actually need to supply an implementation for OAuthAuthorizationServerProvider.GrantAuthorizationCode...
but if you are using the resource owner grant type, you _do_ need to supply an implementation of
OAuthAuthorizationServerProvider.GrantResourceOwnerCredentials. Hmm. Whatever.
Katana and IdenetityServer - two frameworks that are absolute garbage. In the amount of time it took me to
figure out all the observations in this paragraph, I could've written my own /token endpoint."
);
I solved this with the the following simplest example and would like to share it. Hope someone find it helpful.
--
It seems the middleware will check if the key redirect_uri exists in the dictionary of AuthenticationProperties, remove it and everything works fine(with validated context).
A simplified example of AuthorizationCodeProvider woubld be like so:
public class AuthorizationCodeProvider:AuthenticationTokenProvider {
public override void Create(AuthenticationTokenCreateContext context) {
context.SetToken(context.SerializeTicket());
}
public override void Receive(AuthenticationTokenReceiveContext context) {
context.DeserializeTicket(context.Token);
context.Ticket.Properties.Dictionary.Remove("redirect_uri"); // <-
}
}
And don't forget to make the context validated in the overridden method OAuthAuthorizationServerProvider.ValidateClientAuthentication. Again, here's a simplified example which inherit from the ApplicationOAuthProvider class of the template project:
public partial class DefaultOAuthProvider:ApplicationOAuthProvider {
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) {
if(null!=context.RedirectUri) {
context.Validated(context.RedirectUri);
return Task.CompletedTask;
}
return base.ValidateClientRedirectUri(context);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) {
if(context.TryGetFormCredentials(out String clientId, out String clientSecret)) {
// Specify the actual expected client id and secret in your case
if(("expected-clientId"==clientId)&&("expected-clientSecret"==clientSecret)) {
context.Validated(); // <-
return Task.CompletedTask;
}
}
return base.ValidateClientAuthentication(context);
}
public DefaultOAuthProvider(String publicClientId) : base(publicClientId) {
}
}
Note that if you invoke context.Validated with a particular client id, then you will have to put the same client_id in the properties of the ticket, you can do that with the method AuthenticationTokenProvider.Receive

Some questions concerning the combination of ADO.NET, Dapper QueryAsync and Glimpse.ADO

I have been experimenting with a lightweight solution for handling my business logic. It consists of a vanilla ADO.NET connection that is extended with Dapper, and monitored by Glimpse.ADO. The use case for this setup will be a web application that has to process a handful of queries asynchronously per request. Below a simple implementation of my setup in an MVC controller.
public class CatsAndDogsController : Controller
{
public async Task<ActionResult> Index()
{
var fetchCatsTask = FetchCats(42);
var fetchDogsTask = FetchDogs(true);
await Task.WhenAll(fetchCatsTask, fetchDogsTask);
ViewBag.Cats = fetchCatsTask.Result;
ViewBag.Dogs = fetchDogsTask.Result;
return View();
}
public async Task<IEnumerable<Cat>> FetchCats(int breedId)
{
IEnumerable<Cat> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Cat>("SELECT * FROM Cat WHERE BreedId = #bid;", new { bid = breedId });
connection.Close();
}
return result;
}
public async Task<IEnumerable<Dog>> FetchDogs(bool isMale)
{
IEnumerable<Dog> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Dog>("SELECT * FROM Dog WHERE IsMale = #im;", new { im = isMale });
connection.Close();
}
return result;
}
public System.Data.Common.DbConnection CreateAdoConnection()
{
var sqlClientProviderFactory = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
var dbConnection = sqlClientProviderFactory.CreateConnection();
dbConnection.ConnectionString = "SomeConnectionStringToAwesomeData";
return dbConnection;
}
}
I have some questions concerning the creation of the connection in the CreateAdoConnection() method. I assume the following is happening behind the scenes.
The call to sqlClientProviderFactory.CreateConnection() returns an instance of System.Data.SqlClient.SqlConnection passed as a System.Data.Common.DbConnection. At this point Glimpse.ADO.AlternateType.GlimpseDbProviderFactory kicks in and wraps this connection in an instance of Glimpse.Ado.AlternateType.GlimpseDbConnection, which is also passed as a System.Data.Common.DbConnection. Finally, this connection is indirectly extended by the Dapper library with its query methods, among them the QueryAsync<>() method used to fetch the cats and dogs.
The questions:
Is the above assumption correct?
If I use Dapper's async methods with this connection - or create a System.Data.Common.DbCommand with this connection's CreateCommand() method, and use it's async methods - will those calls internally always end up using the vanilla async implementations of these methods as Microsoft has written them for System.Data.SqlClient.SqlConnection and System.Data.SqlClient.SqlCommand? And not some other implementations of these methods that are actually blocking?
How much perf do I lose with this setup compared to just returning a new System.Data.SqlClient.SqlConnection directly? (So, without the Glimpse.ADO wrapper)
Any suggestions on improving this setup?
Yes pretty much. GlimpseDbProviderFactory wraps/decorates/proxies all the registered factories. We then pass any calls we get through to the factory we wrap (in this case SQL Server). In the case of CreateConnection() we ask the inner factory we have, to create a connection, when we get that connection, we wrap it and then return it to the originating caller
Yes. Glimpse doesn't turn what was an async request into a blocking request. We persevere the async chain all the way though. If you are interested, the code in question is here.
Very little. In essence, using a decorator pattern like this adds only one or two frames to the call stack. Compared to most operations performed during the request lifecycle, the time to observe whats happening here is extremely minimal.
What you have looks great. Only suggestion is to maybe us this code to build the factory. This code means that you can shift your connection string, etc to the web.config.

Resources