Authorization through a ASP.NET Web API in Orchard CMS - c#

Creating an ASP.NET Web API module in Orchard CMS is simple and straightforward. The following link explains how to do it and it works just fine. http://www.sebastienros.com/web-api-makes-it-in-orchard
However, the GET requests does not work when the WebAPI is running under Orchard and you use the [Authorize] attribute at the same time.
[Authorize]
public IEnumerable<string> Get()
{
return _moduleManager.GetUsers().Select(n => n.UserName);
}
When I call this from the client
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials = new NetworkCredential("user", "password");
HttpClient client = new HttpClient(handler);
var response = await client.GetAsync("http://localhost:30321/OrchardLocal/api/MyWebAPIModule/Users");
Console.WriteLine(response);
the response variable returns to me the "Not found" HTML page from Orchard. Without the [Authorize], it returns a list of users.
Does Orchard have something already built-in to match the credentials with a registered user in Orchard? Or is there steps missing in the process?

This blog post may be a helpful resource for a deeper understand ASP.NET's Authorize attribute. It might help to look in the web.config file to see what the authentication mode is set to.

I think the problem is that if you are making a call in code, you need to pass any cookies in the request.
A user is authenticated against the website by the use of the aspnetAuth (or FedAuth) cookie, which is provided by the browser. So if you called /OrchardLocal/api/MyWebAPIModule/Users from the browser you would expect this to work (you should see this happen in fiddler by looking at the headers/cookies).
However if you make a call in code you need to pass cookies/auth. header yourself. The call you have does not have any of this, thus it fails (you should see the absence of the cookie in fiddler for this request).
I'm not sure why you would call the api in this way from within your own module. Presumably the API controller calls a service that does the actual workload. You could call this service directly from your Driver/Action, still safe in the knowledge that your business logic is behind the service interface.

Related

Using factory method to create typed HTTP client, ASP.NET Core 2.1

I'm following guides/docs on registering HTTP client within my application. There are couple of services I need to call so I decided to go with "Typed clients".
In order to call another service I need to use OAuth - since this is service-to-service call, when I obtain access token, I cache it + I have setup periodical refresh of token. This means there's another component IAccessTokenCache which gives me access token for service.
Thing I'm struggling to figure out is how to register and configure my typed HTTP client providing it also dependency on IAccessTokenCache.
I'm using ASP.NET Core 2.1 (crucial detail, read on).
HTTP client wrapper looks like this (from: HttpClientFactory in ASP.NET Core 2.1 (Part 2) ):
public class ServiceFooClient
{
public ServiceFooClient(HttpClient client)
{
Client = client;
}
public HttpClient Client { get; }
}
And this is how I register and configure client:
services
.AddHttpClient<ServiceFooClient>(
c =>
{
c.BaseAddress = new Uri("https://www.foo.svc");
// TODO: grab particular access token from cache
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "...");
})
.AddHttpMessageHandler<ResponseMonitorHandler>()
.ConfigureHttpMessageHandlerBuilder(
b =>
{
var handler =
b.AdditionalHandlers.OfType<ResponseMonitorHandler>().FirstOrDefault();
if (handler != null)
{
handler.ServiceName = "Foo Service";
}
});
... I'm already configuring HTTP client and even adding my custom HTTP handler. You can see exact point where I want to access IAccessTokenCache, but I can't.
Possible solutions I can think of:
Configure underlying HttpClient in ServiceFooClient wrapper, like:
// ctor
public ServiceFooClient(HttpClient httpClient, IAccessTokenCache tokenCache)
{
Client = httpClient;
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenCache.GetToken("Foo"));
}
This could work nicely, except I don't configuration decoupling - suddenly dedicated HTTP client has part of configuration in Startup (base URI, additional HTTP handler) and another part in wrapping class (setting authorization header).
Not using AddHttpClient extension method (and others)
I don't really need to call HttpClientFactoryServiceCollectionExtensions.AddHttpClient<T>(...) - I could do all that stuff myself. But as lazy developer... I don't even want to finish this sentence. There's quite a lot of registering inside, so this is just big no no for me.
Upgrade to ASP.NET Core 2.2
Related to previous point - in 2.1, there's no overload of AddHttpClient (2.2: AddHttpClient<TClient>(this IServiceCollection services, Action<IServiceProvider, HttpClient> configureClient)) which would accept callback with service provider. Upgrading to 2.2 would be probably the best solution, yet I will have to be pretty sure that nothing else gets broken (and I already know that there is/was BC break with getting/setting request tracing ID on HTTP context). This could be potentially risky, so I'm trying first to solve my issue in scope of 2.1.
Compare branch of 2.1 with 2.2: HttpClientFactoryServiceCollectionExtensions
Custom HTTP handler setting request headers
Same way as I now register ResponseMonitorHandler, I could register HTTP handler which has access to IAccessTokenCache and sets request authorization header.
But again, as in first case, this decouples configuration of HTTP client. Also if I had several different access tokens, I would either need to implement several HTTP handlers or do some logic deciding what token from cache to use based on request properties.
Finally, question: is there any other way I didn't consider? Is there easy solution of this in ASP.NET 2.1? (... apart of just copy-pasting method from 2.2 of course)
Apparently, there's another extension method in 2.1 ConfigureHttpClient(IHttpClientBuilder, Action<IServiceProvider,HttpClient>) which does exactly what I need!

How to redirect user from OWIN middleware?

I have middleware used for authentication purposes and need to distinguish users by the type if they are internal or external. After this I want to redirect external users to custom error page, because they should not have access to particular section of my site.
I wanted to throw HttpResponseException with my custom status code and handle it by linking in web config's section customErrors with my error page. However I cannot use custom status code this way and to use one of the existing codes is bad idea in my case.
To be honest I am quite new to OWIN middleware and I am not even sure what to google. I will be most grateful for hints how to solve such situation.
Hey take a look at this:
public void Configuration(IAppBuilder app)
{
ConfigureApp(app);
//Some other code here
if (_helper.IsNew())
{
Debug.Write("This is a new guy. Redirect him to the setup page permanently");
var ctx = new OwinContext();
ctx.Response.Redirect("/Setup");//This is how I redirect from Startip.cs
}
}
Observe the code where I am checking in IF for truthy, on true I will create a new OWIN CONTEXT and do redirect there.
I can also specify the redirection status code: 301/302. But without that also the above code works just fine
You should be able to set response code (303 See Other) to the response object in middle-ware and a location header to where you want to redirect user.
When you do that based you you business logic you should not call next function and user will be redirected to new location (if no other middle-ware down the stack will change the response).
Remember to register your middle-ware before web api or mvc.
You can google for web api building custom middleware. Here is an example article you could find Writing Custom Middleware for ASP.NET.

Allow cross site post request on specific ASP.NET Core controller

I am using a complex template for my new ASP.NET Core application. Now I wanted to create a new controller which receives a POST request from another external server. That didn't work. I tried a lot until I found out that there is a mechanism set up which only allows POST request to access my controller which have a certain header (X-XSRF-TOKEN). This is done to prevent a Cross-Site-Request-Forgery attack.
However one specific controller should allow such requests, because this controller is not used from the webpage visitors browser. Is there a way to annotate the controller or any other way to allow this exception?
I finally found the answer and it is indeed possible by using an annotation. Just annotate your controller or action with [IgnoreAntiforgeryTokenAttribute] and the whole XSRF mechanism won't bother your controller any more.
Note that even if you don't intend to use that controller action from a browser, if it can be accessed via http, it may easily be susceptible to CSRF. An attacker may still for example create a rogue webpage, which if visited by one of your users, makes the user send a request to that action. If session management is cookie-based or equivalent and the action changes server state, it would still be an exploitable vulnerability.
So while you can turn of CSRF protection, you need to consider consequences carefully.

Move ASP.NET WebApi 2.0 controller to separate application

We have a WebApi 2.0 application with several controllers, one of which is used to relay data. Due to issues with scalability, we want to move that particular controller out to a separate process so that we can scale it separately from the rest of the application, possibly on a different server altogether. We don't want to break compatibility though, and until we can get all of the clients updated, we will still have requests being made to the old endpoint that controller sat on. What is the simplest way to redirect those requests (it must work with GET/POST/DELETE) to the new location? Does this have to be done within IIS, or is there a way to modify the route? So far we've tried simply returning a redirect response within the old controller, but this doesn't work properly for POST:
public async Task<HttpResponseMessage> Post()
{
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri("http://new/api/endpoint");
return response;
Even if it did, we have some library components that use WebClient with auto-redirect turned off, and those would need to be refactored, which is not ideal. Is there a guaranteed solution?
A redirect is nothing more than an HTTP response with a particular status code and some extra information. If your client application isn't going to follow a redirect than that's not an option for solving your problem.
You could have your Post() method act as a proxy for the other web service. As an example, if your first API is at example.com/Site1 and your second API is at example.com/Site2 then you could have your client make a request to Site1 while Site1 internally makes a request to Site2.

C# Web API - Security for some of the GET requests

On an existing host I've added Web API Models & Controllers. I've added the following four:
Products
Orders
Categories
Users
When someone accesses the localhost:port\api\products, it returns all the products in JSON format.
The Create, Update and Delete statements are completely disabled, so we are only able to use GET-requests on the API (so either \api\products for a list of all products or api\products\# for a single products with id #).
Because the other CRUD's aren't used, there isn't a lot of security that should be added to the Web API, except for one thing: The Users
These will also return emails and such, which would be better to keep private and unreadable without the proper authorization (without entire log-in pages, but a way to authenticate yourself when accessing the Web API in for example Android HttpGetRequests).
So, the question: How should I add authorization for only the UsersController accessed by the Web API.
And, how can I encrypt the JSON in C# and decrypt it in Android again. If this second part is too big to answer I'll make a new question later on, my main focus is the low-end [<- without log-in pages, so built in into the GET-request] authorization of the Web API's GET-request for Users.
Edit 1: I did found this link where a new project is made with Authorization Changed to Individual Users. I also see that the user is registered and then logged in with POST and GET requests.
The following questions came into mind when reading through this link:
How to change the Web API's Authorization to Individual Users on an existing project?
Our authorization is done through OAuth (mainly Google-account) with our work e-mail address. I guess it's not possible / easy to authorize in the same way as in the link with a Google-account on Web API GET-requests.
Edit 2: After using the first link provided by Vladimir Gondarev I've added the [Authorize] to both the Get methods in the UsersController. In my project everything else was already used before, like a class that uses the AuthorizeAttribute, so just adding the [Authorize] was already enough for the first step. Now in the browser I get an unauthorized (JSON) back when I'm not logged in, which is good.
The next step would be to add the OAuth-authorization to the Android app, but that is an entire new problem / question that I will look into first before asking a new stackoverflow-question.
The simplest solution would be "Basic Authentification". In order to to implement it you have to derive from AuthorizeAttribute and then apply it to a method or a controller.
Here you find further info:
What is basic Authentification:
http://www.asp.net/web-api/overview/security/basic-authentication
Implementation:
ASP.net Web API RESTful web service + Basic authentication
You don't have to encrypt anything as long as you use HTTPS transport.

Categories

Resources