I need to authenticate every request to wcf services
public class AuthenticationInterceptor : RequestInterceptor
{
public AuthenticationInterceptor() : base(false)
{
}
public override void ProcessRequest(ref System.ServiceModel.Channels.RequestContext requestContext)
{
//How to access Request Header (Authorization header) from here?
}
}
You can get the headers from the System.ServiceModel.Channels.Message, so try
var message = requestContext.RequestMessage;
var request = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
string authorization = request.Headers[HttpRequestHeader.Authorization];
Related
After the user logs in I verify their info and generate a JWT token.
Authentication process happens with Authentication (it's not my custom handler).
Where and how do I save this token so it will be sent along the http calls? I don't want to save it in the client side because of XSS attacks. The following doesn't seem to work either as I wont be in every request
HttpContext.Request.Headers.Append("Authorization", MyGeneratedJWTTokenAsString);
I have found answers that use HttpClient.Request but is there any other secure way of doing this?
When using HttpClient in a backend service, it is always good to use the IHttpClientFactory to generate clients.
So, what we are going to do is use this factory (in conjunction with IHttpContextAccessor) to produce HttpClient objects that have the current user's authorization scheme and token. So, add this to your ConfigureServices method in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddHttpClient("UserAuthorizedHttpClient", (sp, httpClient) =>
{
var accessor = sp.GetRequiredService<IHttpContextAccessor>();
if (accessor.HttpContext.Request.Headers.TryGetValue(
"Authorization", out var authHeaderValue) &&
AuthenticationHeaderValue.TryParse(
authHeaderValue, out var auth))
{
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(auth.Scheme, auth.Parameter);
}
else
{
// incase there is a value from a previous generation
if(httpClient.DefaultRequestHeaders.Contains("Authorization"))
{
httpClient.DefaultRequestHeaders.Remove("Authorization");
}
}
});
services.AddHttpContextAccessor();
// ...
}
In order to use these special clients, you simply inject IHttpClientFactory in to the service that needs to make the HTTP requests:
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace YouApplicationNamespace.Services
{
public interface IMyHttpRequesterService
{
Task DoSomethingCoolAsync();
}
public sealed class MyHttpRequesterService : IMyHttpRequesterService
{
private readonly IHttpClientFactory _httpClientFactory;
public MyHttpRequesterService(IHttpClientFactory httpClientFactory) =>
_httpClientFactory = httpClientFactory;
public async Task DoSomethingCoolAsync()
{
var authroizedHttpClient =
_httpClientFactory.CreateClient("UserAuthorizedHttpClient");
var resp = await authroizedHttpClient.GetAsync(new Uri("https://www.example.com/"));
// ...
}
}
}
As long as you use the same name, you will get a client that uses the AddHttpClient routine in your configuration.
(Please note: this code is not tested. It is more of a guideline)
I'd like to implement a filter that skips validation of an antiforgery token when an auth token authentication (Bearer) is used.
In the ASP.NET Core 2.2 the ValidateAntiforgeryTokenAuthorizationFilter and AutoValidateAntiforgeryTokenAuthorizationFilter were public (even though living in the Microsoft.AspNetCore.Mvc.ViewFeatures.Internal namespace), so I was able to just inherit from the latter and override the ShouldValidate method easily.
In the ASP.NET Core 3.0 they became internal, so it's not possible to just inherit from them. I can just copy-paste the code, but it's not the ideal solution obviously.
I was following the Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core article from MSDN, but it doesn't really mention anything relevant to my scenario.
Normally you can use [IgnoreAntiforgeryToken] attribute if you can determine at compile-time that the csrf token should be ignored. If you want such an ability at run-time, you could create a custom FilterProvider that will provide an IAntiforgeryPolicy if there's a Authroization: Bearer json-web-token header.
For example, we can create a custom AutoSkipAntiforgeryFilterProvider as below:
public class AutoSkipAntiforgeryFilterProvider: IFilterProvider
{
private const string BEARER_STRING = "Bearer";
public int Order => 999;
public void OnProvidersExecuted(FilterProviderContext context) { }
public void OnProvidersExecuting(FilterProviderContext context)
{
if (context == null) { throw new ArgumentNullException(nameof(context)); }
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
{
var headers = context.ActionContext.HttpContext.Request.Headers;
if (headers.ContainsKey("Authorization"))
{
var header = headers["Authorization"].FirstOrDefault();
if(header.StartsWith(BEARER_STRING,StringComparison.OrdinalIgnoreCase))
{
var FilterDescriptor = new FilterDescriptor(SkipAntiforgeryPolicy.Instance, FilterScope.Last);
var filterItem = new FilterItem( FilterDescriptor,SkipAntiforgeryPolicy.Instance);
context.Results.Add(filterItem);
}
}
}
}
// a dummy IAntiforgeryPolicy
class SkipAntiforgeryPolicy : IAntiforgeryPolicy, IAsyncAuthorizationFilter
{
// a singleton
public static SkipAntiforgeryPolicy Instance = new SkipAntiforgeryPolicy();
public Task OnAuthorizationAsync(AuthorizationFilterContext context) => Task.CompletedTask;
}
}
And register this filter provider in Startup :
services.TryAddEnumerable( ServiceDescriptor.Singleton<IFilterProvider, AutoSkipAntiforgeryFilterProvider>());
Now it will bypass the AntiForgery even there's a [ValidateAntiForgeryToken]attribute.
[Demo]
Assume we have an action method annotated with [ValidateAntiForgeryToken]:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] XModel xModel)
{
....
}
Normally, it will protect this method with CSRF token. But if you send a request like:
POST /XModels/Create HTTP/1.1
Authorization: Bearer Xyz
Content-Type: application/x-www-form-urlencoded
...
it won't validate the csrf token.
On a blazor client application, what is the equivalent of jQuery ajax WithCredentials or JavaScript credentials: 'include'?
With Javascript I am able to say:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
which includes auth cookie while making request and server responds with 200. I am trying to write same with Blazor using HttpClient.
You can no longer set WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include; in your Startup file to achieve js`s credentials: 'include'
To achieve this in newer versions of blazor, you need to create a class that derives from DelegatingHandler, override SendAsync method and set BrowserRequestCredentials for request to BrowserRequestCredentials.Include
public class CookieHandler : DelegatingHandler
{
public CookieHandler()
{
InnerHandler = new HttpClientHandler();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
return await base.SendAsync(request, cancellationToken);
}
}
After it pass your CookieHandler to HttpClient
builder.Services.AddScoped(sp => new HttpClient(new CookieHandler()) { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
In your Startup.Configure method you can set the WebAssemblyHttpMessageHandler.DefaultCredentials to the required value of the 'credentials' option on outbound HTTP requests like this:
public void Configure(IComponentsApplicationBuilder app)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY")))
{
WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
}
app.AddComponent<App>("app");
}
References:
https://github.com/aspnet/AspNetCore/blob/c39fbb8f12002f61df6c093b0c11e6bd585ee202/src/Components/Blazor/Blazor/src/Http/WebAssemblyHttpMessageHandler.cs
https://github.com/aspnet/AspNetCore/blob/5a70f5312fb57fc3788e5af56a99e7b43761e195/src/Components/Blazor/Blazor/src/Http/FetchCredentialsOption.cs
https://github.com/aspnet/AspNetCore/blob/d18a033b1ee6d923a72d440718c5d496b57c2ffc/src/Components/test/testassets/BasicTestApp/Startup.cs
Hope this helps...
I have a backend service which accepts Authorization header to validate access. I created a Gateway service with Spring cloud zuul and routed requests to backend service.
Gateway service itself is protected with OAuth2 and accepts a Authorization header to validate access. Now once the request authorizes to gateway service, Gateway service act as a client to send an updated Access token in the header by using it's clientid,secret and backend service resource ID. As it has to send Authorization header, I was trying to update the Authorization header in the request but it is taking for below two ways.
ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader("Authorization", accessToken);
With the above code it is adding Authorization header but it is adding it to zuul headers which the backend service is not identiyfying.
I have created a wrapper to modify the request object but it is not working
public class RequestWrapper extends HttpServletRequestWrapper
{
private final Map<String, String[]> modifiableParameters;
private Map<String, String[]> allParameters = null;
public RequestWrapper(final HttpServletRequest request,
final Map<String, String[]> additionalParams)
{
super(request);
modifiableParameters = new TreeMap<String, String[]>();
modifiableParameters.putAll(additionalParams);
}
#Override
public String getParameter(final String name)
{
String[] strings = getParameterMap().get(name);
if (strings != null)
{
return strings[0];
}
return super.getParameter(name);
}
#Override
public Map<String, String[]> getParameterMap()
{
if (allParameters == null)
{
allParameters = new TreeMap<String, String[]>();
allParameters.putAll(super.getParameterMap());
allParameters.putAll(modifiableParameters);
}
return Collections.unmodifiableMap(allParameters);
}
#Override
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(getParameterMap().keySet());
}
#Override
public String[] getParameterValues(final String name)
{
return getParameterMap().get(name);
}
}
Above wrapper is found from http://www.ocpsoft.org/opensource/how-to-safely-add-modify-servlet-request-parameter-values/
and called it in the zuul filter
authToken = getAuthToken();
String accessToken = "Bearer " + authToken;
Map<String,String[]> additionalParams = new HashMap<>();
additionalParams.put("Authorization", new String[] {accessToken});
ctx.setRequest(new RequestWrapper(request, additionalParams));
What am I doing wrong or any other way of modifying request header?
if you are asking about how to add headers to Zuul request, your code is correct but you should verify the Filter type (Pre, Route, Post, ...) and the ORDER of your filter.
Check this thread : Adding Headers to Zuul when re-directing
And maybe this can helps too : How to select route based on header in Zuul
If you need to pass authorization through Zuul to backend service, you can check sensitiveHeaders property. Something like :
zuul.routes.YOURSERVICE.sensitiveHeaders=Cookie,Set-Cookie
I have NET Core 2 Web API application. During the process i have to invoke Client A's API to get some data. So i am using HttpClient to invoke it. Client A also requires me to pass userid and password in header.
So instead of directly injecting HttpClient i have wrapper around HttpClient something like below
public class ClientA : IClientA
{
private readonly HttpClient _httpClient;
public ClientA(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetData()
{
return await _httpClient.HttpGetAsync("someurl");
}
}
Then use ClientA in Service
public class MyService :IMyService
{
private readonly IClientA _clientA
public MyService(IClientA clientA)
{
_clientA= clientA
}
public void DoSomethig()
{
_clientA.GetData();
}
}
Then i am registering everything in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService, MyService>();
services.AddScoped(factory =>
{
Func<Task<IClientA>> provider = async () =>
{
using (var dbContext = factory.GetService<MyDBContext>())
{
// get userid and password from database here
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("UserId",userid);
httpClient.DefaultRequestHeaders.Add("Password",password);
return new ClientA(httpClient);
}
};
return provider;
});
}
However i am getting error
System.InvalidOperationException: Unable to resolve service for type
'System.Net.Http.HttpClient' while attempting to activate
'XXXXXXXXX.ClientA'. at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type
serviceType, Type implementationType, ISet1 callSiteChain,
ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type
serviceType, Type implementationType, ISet1 callSiteChain)
remaining exception removed for brevity
Notice that during registration i am newing-up instance of HttpClient and passing it to ClientA class because i have to set userid and password.
To get rid the above error I can register HttpClient with UserID and Password with DI framework and i guess that would work.
However, in that case, if have another client, ClientB, that takes HttpClient then DI framework will inject same httpclient that has userid and password. and that will create security issue because ClientB would see ClientA's credentials in request headers.
public class ClientB(HttpClient client)
{
private readonly _httpClient;
public class ClientB(HttpClient client)
{
_httpClient = client;
}
public string CallClientB(string url)
{
// here ClientB will receive ClientA's credentials
return await _httpClient.HttpGetAsync(url);
}
}
You don't want to be instantiating httpclient in a scoped context, that is creating an instance of httpclient per request which is not the recommended usage pattern for that class. (won't scale well). https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
Create a singleton with a separate interface per customer (assuming a small number of customers) - possibly with a code access security demand in its implementation, depending on your setup (identity impersonation enabled?)
That will a) scale well b) only run once per customer per application instance/startup and c) enforce an access check for usage.
Also, this answer is connected and relevant to your header requirements - HttpClient single instance with different authentication headers
resolved my issue
services.AddScoped<IClientA>(factory =>
{
var dbContext = factory.GetService<MyDBContext>();
// get userid and password from database here
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("UserId",userid);
httpClient.DefaultRequestHeaders.Add("Password",password);
return new ClientA(httpClient);
});