Testing WebAPI actions that have authorization filters - unit-testing

I’ve got a Web API that I’ve added [Authorize] attributes to, which means that the unit tests I had previously now fail due to them being unauthorised. Here’s a sample of a basic test along with an initialiser method:
[TestInitialize]
public void CreateServer() {
var config = new HttpConfiguration();
WebApiConfig.Configure(config); // Create the routes
var server = new HttpServer(config);
this.client = new HttpClient(server);
}
[TestMethod]
public void MyThings_GET_Returns_All_MyThings() {
var response = this.client.GetAsync("http://localhost/api/1.0/mythings").Result;
var mythings = response.Content.ReadAsAsync<IEnumerable<MyThing>>().Result;
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(4, mythings.Count());
}
What I’m wondering is if there’s any way that I can either make my test log in so that it passes the authorization filter, or if there’s any way that I can pass as ASPXAUTH cookie along with the HttpClient request? Or another way of passing authorization that I haven’t thought of?
Nothing I’ve tried seems to work and I’m struggling to find any helpful info anywhere.
Thanks in advance.

What does your Authorize attribute do when it performs the authorization check? There are quite a few options that come to mind:
Have the authorize filter support multiple means of getting the "authorization token" that it requires (e.g. through an HTTP header or a querystring parameter, etc)
Right after your test initialization, clear out the filter from the configuration (so that it is not called at all). If you choose to go this route then you may wish to pop in a new filter that sets any authorization values that might be used further along the pipeline
If you are using dependency injection, move the "authorization check" into some sort of IAuthorize location that can be updated in your configuration
I would also recommend using RestSharp for making queries to your endpoints as it does a very good job of specifying headers, parameters, etc.

I decided that the way I was going about the problem was fundamentally wrong. Using cookie-based authorisation with Web API is just not a good idea, so I’ve decided to get rid of the authorize attributes and perform API-Key-based authentication instead. This makes it easier to test as I can just pass the correct API key in the request, but also means that I’m not relying on cookies for authorisation.

Related

ckan.toolkit.redirect_to does not redirect

I'm currently developing an ckan extension, where i need to redirect to a url on a different domain.
In my plugin i defined a custom action function:
#side_effect_free
def download_json(context, data_dict):
toolkit.redirect_to('http://my.json-builder.com?id=1234')
But when i call this endpoint i just get following response:
response screenshot
So i assume that the action function is called, but the redirect_to call does not redirect to the url i defined.
Thanks for your help!
Florian
It's a bit hard to figure out what you're trying to accomplish but here's a few things I hope will help.
Short Answer:
No, you can't redirect from an API endpoint in CKAN. The endpoint response in CKAN is built up and expects certain things from your action. Your action should return some kind of result. In your case it's returning nothing but trying to redirect. A logic action function with IActions is not the same as a Blueprint or pylons controller action.
See Making an API request docs, specifically the breakdown of an API response in CKAN. Also, you can review the pylons implementation that builds up the API response or the flask blueprints implementation.
More Info to help with your approach:
You say you are trying to call an endpoint that redirects a user to a different domain url. Based on this consider the following:
The first thing I thought you wanted was to have a url that someone goes to through the web interface of your site and are redirected to another site. In this case your example code of toolkit.redirect_to('http://my.json-builder.com?id=1234') makes sense and works for a custom controller action using/implemented with IRoutes or if you're using flask then IBlueprint. A User would go to a URL on your site such as http://localhost.com/download_json and be redirected to the new URL/site in their browser.
If you are intending this to be an API call for other users this starts to feel a little bit odd. If a user is using your API, they would expect to get results from your site in JSON CKAN's API is designed to return JSON. Someone consuming your API endpoint would not expect to be redirected to another site e.g. if I called http://localhost.com/api/3/action/download_json I would expect to get a JSON object like
{
help: "http://localhost/api/3/action/help_show?name=download_json",
success: true,
result: {
...
}
}
They would look for success to make sure the call worked and then they would use the result to keep moving forward with their desired processes. If you do want someone via an API to get redirect info I'd likely return the redirect url as the result e.g. result: {'redirect_url': 'http://my.json-builder.com?id=1234'} and document this well in your extension's API docs (e.g. why you're returning this endpoint, what you expect someone to do with it, etc).
If this is an API call for your own extension I'm guessing what you are trying to do is use my.json-builder.com to build a json of something (a dataset maybe?) and return that json as the result at your endpoint or maybe even consume the result to make something else? If that's the case, then in your function you could make the call to my.json-builder.com, process the results and return the results to the user. In this case, you're not actually wanting to redirect a user to a new site but instead make a call to the new site to get some results. If you actually want the results for your extension you don't need an additional endpoint. You could make the call from your extension, consume the results and return the desired object you're trying to create.
Hope this helps and sorry if I've miss-understood completely.

best way to access req.body in policy

I am currently working on a custom plugin realizing an oauth solution. I decided to implement a proper policy that forwards the incoming login post to an external service. Therefore I have to access the body of the request (property req.body), which is only possible when the required body parser is enabled as express - middleware. Unfortunately, I could not find a comfortable way to enable body parsing within the gateway application. Consequently, I made a workaround by registering a proper route in order to access the underlying expressapp object.
pluginContext.registerGatewayRoute(app => { app.use(express.json()); }
I do not want to substitute the policy by simply registering a route, because I did not find a way to apply other policies (e.g.: CORS, RATE LIMITER...) to this route.
Please let me know if I oversee something and there is an easier way to enable body parsing.
yes, using "registerGatewayRoute" will apply middleware to every route in EG. What you can do is create a body parser policy. Policy in EG is just a wrapper around ExpressJS middleware so
so body parser policy can contain code like
{
name: 'bodyparser',
policy: (actionParams) => express.json()
}
https://www.express-gateway.io/docs/plugins/policy-development/
Now just add this policy as first one in the pipeline and it should provide req.body for all routes going through that pipeline
Thanks a lot for your helpful answer. As suggested I created a bodyParser policy. Only a small modification of the previous answer was necessary: Instead of express.json I had to call the function express.json() in order to get required middleware functionality.
const express = require('express');
module.exports = {
name: 'bodyParser',
policy: (actionParams) => express.json()
};
Works fine now and body parsing is only enabled where it is really required.

ember: using cookies with ember-network

Can cookies be used with ember-network requests? Thanks to this answer I know that they can be used with ember-data API requests, but I need to do a network request in an initializer and it doesn't appear the ember-data store can be accessed that early.
Background:
I'm wanting to persist shopping cart data to the backend for these reasons
The ember-cart addon has a smart way of persisting the cart by jsonifying and data model and dumping to localstore when it changes:
window.localStorage.setItem('cart', JSON.stringify(this.payload()));
then upon return visit parsing the json and pushing it into the store in an instance initializer:
...
payload = JSON.parse(payload);
...
cart.pushPayload(payload);
I'd like to do basically the same thing, but instead of getting the JSON from localstorage, get it from the API via the network.
the store ins't available in an initializer, but ember-network is. So hypothetically I think I can do this. The problem I'm running into is that the cookie isn't being passed.
I get around this with ember-data by using this:
xhrFields: {
withCredentials: true
}
in the application adapter, but I can't find any info about whether there's a similar setting for ember-network. I see the request to my API being made in the initializer, but the api doesn't return anything because the browser cookie isn't included.
The fetch API provides a credentials option..
This is also documented at the whatwg-fetch library used by ember-network.
So basically you can do
fetch("/foobar", { credentials:"include" }).then(...)

How do we use uri endpoint mapping in spring integration

I am trying to configure spring integration using annotation. Instead of payloadqnameendpoint mapping I would like to use URI endpoint mapping. I found many examples with default URI endpoint but I required an annotation example without default end point.
Let's take a look to the AnnotationActionEndpointMapping support in the Spring WS! As you see it is based on the division between POJO methods and annotations on the them. The POJO is a main word there. This kind of framework magic allow us to separate low-level protocol from end-application business logic. From other side Spring Integration's AbstractWebServiceInboundGateway implements MessageEndpoint meaning that the whole SOAP hard work will be done in this implementation. It isn't a POJO.
Of course this topic is a different story, but you should understand from here that MessageEndpoint and MethodEndpoint work a bit different. At least they do messaging logic from different levels of SOAP request.
So, we really can't map <int-ws:inbound-gateway> with #Action or similar just because it is a whole SOAP endpoint already.
From other side, having AnnotationActionEndpointMapping from Java config, you can fully get rid of <int-ws:inbound-gateway> and configure your Endpoint to delegate desired #Action to the methods of #MessagingGateway. And it will work beucase the hard SOAP work has been done already by Spring WS framework.
I don't know you that this code will work, but you can check or let me know and I'll test it and come back to again:
#Endpoint
#MessagingGateway
public interface OrderEndpoint {
#Action("http://samples/RequestOrder")
#Gateway(requestChannel = "getOrderChannel")
Order getOrder(OrderRequest orderRequest);
#Action("http://samples/CreateOrder")
#Gateway(requestChannel = "createOrderChannel")
void order(Order order);
}

How do I integrate ServiceStack and DotNetNuke to provide REST services within a DNN authenticated context?

DotNetNuke 6.2 has a Services Framework that does something similar
http://www.dotnetnuke.com/Resources/Wiki/Page/DotNetNuke-6-2-Developer-Quick-Start.aspx#Services_Framework_18
The single biggest convenience of Services Framework is that authentication, authorization and establishing a DotNetNuke context are all built in.
How do I integrate ServiceStack (http://servicestack.net) with DotNetNuke to provide authentication, authorization and establish a DotNetNuke context? Any pointers?
I wrote the DNN implementation, so I can tell you about how it works. I don't know the details of ServiceStack so I can't tell you how to apply it there. When I first set out to build this, I expected it to be much more complicated than it actually is. You really only need a handful of calls into the core.
Establishing context and authentication occurs during initialization of the DnnController. One of the great things about DNN being all open source is that all these sort of details are public. Here is a link to the DnnController.cs
And here are the most interesting bits:
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
LoadDnnContext(requestContext.HttpContext);
AuthenticateRequest(requestContext.HttpContext, PortalSettings.PortalId);
}
protected virtual void AuthenticateRequest(HttpContextBase context, int portalId)
{
if (!context.Request.IsAuthenticated)
{
BasicAuthenticator.Instance.TryToAuthenticate(context, portalId);
}
if (!context.Request.IsAuthenticated)
{
DigestAuthenticator.Instance.TryToAuthenticate(context, portalId);
}
MembershipModule.AuthenticateRequest(context, true /*allowUnknownExtension*/);
}
protected virtual void LoadDnnContext(HttpContextBase context)
{
var domainName = TestableGlobals.Instance.GetDomainName(context.Request);
var alias = TestablePortalAliasController.Instance.GetPortalAliasInfo(domainName);
int tabId;
ValidateTabAndModuleContext(context, alias.PortalID, out tabId);
var portalSettings = new PortalSettings(tabId, alias);
context.Items["PortalSettings"] = portalSettings;
}
The Service Framework forces all routes into the form {unique portal path}/DesktopModules/{ModuleName}/API/{url} . The unique portal path is important to easily identifying the portal to which the request was sent. In most cases DNN will allow a URL of the form /Default.aspx?portalid=n, but Service Framework won't accept that, it requires that the request path match the portal alias e.g. mysite.com/childportal/... This requirement ensures that GetDomainName() will work.
I should mention that the TestableXXX classes are in the Internal namespace and therefore are not part of the official public API, and are subject to breaking changes between releases. Most of the methods on the classes have a public analog which is harder to mock but otherwise equivalent. If it is reasonable for you to make small code fixes before upgrading your servers, feel free to use the Testables. If you don't have complete control over the upgrades of your servers you should avoid the .Internal namespaces.
Service Framework supports authentication against the permission of a specific module instance. Services tied to a module must provider tab and module ids. If your services are not module specific you may omit this, and use a tabid of -1 in the PortalSettings.
ServiceFramework has it's own implementations of basic and digest auth since MVC does not provide them. I beleive that ServiceStack does provide Basic and Digest, so you probably only need to make the call to MembershipModule.AuthenticateRequest().