Conditional Attribute Routing - asp.net-web-api2

When using attribute routing, is it possible to remove routes based on certain runtime condition - such as licensing?
Something like this:
[LicensedRoute("/api/whatever")]
where '/api/whatever' is only added to the route table if the application is licensed.
Obviously I can explicitly do the check in the action method or use an action filter to validate the requests but ultimately I prefer the route not to be available if the software is not licensed.

Seems you need Attribute Routing: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
Is it RESTful? How you store the licensing info: is it user logins? tokens? key?
You could do it RESTful and force the client to pass a token every time via token-based authentication, for example: define several "licence" levels/types (eg. Free/Trial/Basic/Pro) and then in a persistent storage (table) map tokens (guids) to a licence type.
Then using a custom attribute, mark each endpoint/controller/action with the minimum required licence type to be accessible (e.g. [MinimumLicence("Basic")]). And then create "routing tables" based on the licence required.
In this case you would deny access to routes rather than "remove" them.

Related

Use WSO2IS to configure user access to entities

I'm trying to implement WSO2IS for authorization. My understanding is that in the WSO2 realm, the concept of a permission broadly restricts a user's access to an action, or a resource. So, for instance, if my app is a bookstore, I could configure whether a user has "read" access to authors at large, and toggle their access to the GetAuthors() endpoint. However, I need to configure a user's access to certain authors. Is there a way I can store a whitelist of authors on a per-user basis? What I'd like to accomplish is to have a user call a GetBooks() endpoint and return only the books written by the authors that the user can access.
It sounds like one possibility is to store this information in an external datastore, and implement a custom PIP to read from that datastore.
Another possible option would be to create a custom attribute on the User type and store the whitelist of author IDs in an array on each user.
Is there a better way to do this? I'd prefer not to implement a custom external datastore just to store relationships between users and entity ids. Is it possible to do this with XACML and policies? Is it possible to have WSO2IS stick this information on a claim that is returned to my controller so that I can limit my underlying query based on the user's whitelist of allowed entity IDs?
AFAIU you need to maintain a claim to track the accessibility for reading. You can easily create a custom claim to track it by following the article[1]. In this way, you can refer to the custom claim at the controller to make further decisions.
You have to update this claim value for each user. For this, you can use SCIM API[2] by following doc[3] to extend the SCIM endpoint for custom claims.
[1]https://medium.com/#inthiraj1994/lets-add-a-custom-claim-to-oidc-in-wso2-is-d871e418d6b0
[2]https://is.docs.wso2.com/en/latest/develop/scim2-rest-apis/#/scim-20-api-definition
[3]https://is.docs.wso2.com/en/latest/develop/extending-scim2-user-schemas/#extending-scim-20-user-schemas

Ignore or not API endpoint parameters based on access level

I am working on an API endpoint that returns a list of products:
"api/products"
The endpoint accepts the following parameters:
page_size
page_number
Each product has a boolean property named IsApproved.
In the web application used by common users I always want to return only the Approved products ... On the web ADMIN application used by administrators I want to return all products, Approved or Not ...
My idea would be to add a new parameter (enumeration) named:
ApprovedStatus
And the values would be Approved, NotApproved and All.
On each API call I would check the user permissions ... If is admin I will consider the value on this parameter. If not then I will always return only approved products.
Another solution would be to have different endpoints ...
Any advice on which approach to take or is there other options?
The approval status is part of the product, therefore, in a perfect REST world, you don't want a different endpoint at all since you're accessing the same resource.
Then, for filtering a resource based on a property value, I think the convention is that if you specify that property as a query parameter it will only return those matching the value, and if not, it will return all of them, so I don't see the need to define a special ApprovedStatus parameter with some special values. Just query by isApproved!
Finally, about how to handle authorization. This, I think, should be handled at a completely separate layer**. If authorization is involved, you should have an explicit authorization layer that decides, for a specific resource and user, wether access is granted or not. This means the query would be triggered and if one of the resources generated by the query fails to be authorized for the user that triggered the query, it's taken out of the results. This accomplishes the behaviour you want without having any code that is checking specific users against specific query parameters, which is good because if tomorrow you have another endpoint that exposes this objects you won't have to implement the same authorization policy twice. Pundit is a perfect example on how to do this with Ruby elegantly.
**Of course, this approach retrieves data from the database unnecessarily which could matter to you, and also opens your endpoint up to timing attacks. Even then, I would consider tackling these problems premature optimizations and should be ignored unless you have a very good reason.
You're right about your ideas:
You can create a new endpoint just for admins, that will return all products
You can use a kind of authorization (e.g. Authorization Header) in order to check if the API is being called through admin or normal user. Then you can route internally to get all products or just IsApproved products.
You can add a proxy in front of your API to route to the right action, but it can also be achieved directly in the API but I think the second solution is easier.
Adding one more property is a bad idea.
In my opinion, adding another end point is very good. Because it will increase the protection in the admin end point.
Otherwise, since it is a web application, Simply set a cookie and a session to identify and separate the admin and user.
Going with the principle of least astonishment, I'd be in favour of adding a second endpoint for admin users. Such that you'll have:
GET /api/products (for regular users)
GET /api/admin/products (for admins)
This allows your code and API documentation to be nicely separated, and all of the admin-specific authentication details can live under the "admin" namespace.
The intention behind each API call is also clearer this way, which helps developers; and means that you can differentiate between admin vs regular usage in any usage stats that you track.
With ApprovedStatus, I think the specifics here don't matter much, but - considering what a developer using the API might reasonably expect / assume - it would be good to:
Ensure the ApprovalStatus parameter name matches the property name for "approval" that you return with each product object
Defaults to "approved" if it is not specified
Alert the user when an invalid value is specified, or one that they don't have access to
Bottom line: to answer your headline question - I think it's bad practice to ignore user input... sometimes. Design your API such that distinctions around when input can be passed in is very clear; and always alert the user if you receive input values that are technically acceptable, but not in the way that the user has requested, or for their access level. Ignoring values that are plain wrong (e.g. an argument that doesn't exist) is another story, and can be useful for future proofing or backwards compatibility.

Architecturing testmode/livemode using OAuth 2 token

The title is a bit obscure. I'm interested about some feedbacks on a specific architecture pattern.
Let's take as an example the Stripe API: when you are using this API, the system is basically broken into two parts: live mode and test mode. If you hit the "/customers" end-point, you can either retrieve test mode customers or live mode customers, based on the type of API key used.
I'm asking myself how I could implement such a pattern using an OAuth 2 access token.
In my workflow, I have a single application page (JavaScript) that communicates through my API. I have a "live"/"test" switch, so basically my whole website is replicated into two distinct environments.
When I log in into my application, my authorization server creates a unique access token (OAuth 2 Bearer token), that is send for each requests. But obviously, my access token is tied to the "session", not an "environment" (live or false), so if I want to implement a switch live mode / test mode, I cannot rely on the token, because the token is "generic".
I've thought about two options:
Depending on live mode or test mode, I send an additional header to all my request (like X-Livemode which is either true or false). Then, in my back-end, I reuse this header to automatically adds a filter on all my requests.
If I switch to live mode or test mode, I ask my authorization server another access token. This would means that access token would have additional context information. However this seems a bit complicated, and I'm not sure that OAuth 2 spec allows token to have such additional information.
I'm not sure if this post is clear or not :p.
The second part of the question, is what is the best way to implement such a system where all the resources are basically duplicated between live / test mode ?
In my understand, it should be as simple as adding a "isLivemode" property to all resources, and make sure that all my SQL queries are aware of this. Is this correct?
Thanks!
A much simpler solution I've used in the past (albeit a bit of a workaround) is just to append "live" or "test" (base64 or hex encoded) to the api key, like so:
Imagine your actual key is:
9a0554259914a86fb9e7eb014e4e5d52
In your key presentation, present your key to the user as:
9a0554259914a86fb9e7eb014e4e5d526c697665
Then use a regular expression to strip off the known characters.
Alternatively, if you're equipped to handle key-value maps, a more "OAuth2-spec" approach would be to generate unique keys for live and test and do a key-value map lookup on the request to determine if one belongs to live or test.

RESTful way of having a single resource based on authentication

I have an API that provides an Account resource based on the authentication (login) that is supplied. As a user can only have one account, and can only see it's own account and not those of others, this API will basically be a single resource API in all cases.
So to keep things simple, I have this resource under the url accounts/ and when you access accounts/?username=dude&password=veryhard you'll get your account data (if you dohn't supply authentication you'll get a 403).
Now I wonder if this is RESTful. Also, you should be able to update your account info, and I wonder if PUT would be appropriate. In my knowledge, PUT should be done on a unique URI for the resource. Well, is this a unique URI for the resource? Generally a URI for an account would look like accounts/3515/ where 3515 is the account id. However, users don't know their account id. Also, there should be more ways to log in, instead of a username + password you should also be able to use a token (like accounts/?token=d3r90jfhda139hg). So then we got 2 URL's that point to the same resource, which also isn't really beautiful for a RESTful URI, is it?
So, what would be the most RESTful solution? Or should I not do this RESTful?
REST purists will consider that use of /accounts/ to obtain a single account is bad practice as it should specify a collection. Instead consider a key which cannot be mistaken for an ID, for example if your IDs are UUIDs then use a token such as 'me' so your URL is /accounts/me. This has the advantage that if later on you wish to obtain different account information, say for example you need to list users or you have an administration system using the same API, then you can expand it easily.
Putting username and password in the URL is also not pure REST. The query parameters should be directly related to the resource you are obtaining; commonly filtering and limiting the resources returned. Instead you should seriously consider using something like HTTP Basic authentication over an encrypted (HTTPS) connection so that you separate out your authentication/authorisation and resource systems. If you prefer to use a token system then take a look at oauth or hawk.
Finally, yes if you use PUT you should supply a full resource identifier. Given that it is very common for systems to read data before updating it the lack of ID won't be a problem as that will come back as part of the prior GET.
Yes accounts/?username=dude&password=veryhard is a correct REST URL.
PUT is used with an id if it used to update a resource, if you use it to create you must supply an ID. otherwise you use post to create a resource without id

WIF STS, different "kinds" of users, applications and claims

We are currently looking into implementing our own STS (Microsoft WIF) for authenticating our users, and in that process we have come up with a few questions that we haven’t been able to answer.
We have different kinds of users, using different kinds of applications. Each kind of user needs some special types of claims only relevant for that kind of users and the application belonging.
Note that we do not control all the clients.
Let’s say that all users are authorized using simple https using username and password (.NET MVC3). A user is uniquely identified by its type, username and password (not username and password alone). So I will need to create an endpoint for each user type, to be able to differentiate between them. When a user authorize, I’ll issue a token containing a claim representing the user type. Is there an easier way for doing this? Can I avoid an endpoint for each user type (currently there are three)?
My token service can then examine the authorized users’ token and transform the claims, issuing a token containing all the users’ type specific claims. So far so good, except for the multiple endpoints I think?
If I need to have multiple endpoints, should I expose different metadata documents as well, one for each endpoint? Having one big metadata document containing a description of all claims, doesn’t make any sense since there is no application that needs all claims.
Update
Some clarifications.
Certain applications are only used by certain types of users. Not one application can be used by multiple user types.
Depending on what type of application the request is coming from, username and passwords needs to be compared for that user type. There are user stores for each type of application. That is why I need to know what application type the request is coming from. I can't resolve the type by the username and password alone.
Based on your problem description, it sounds like you have three indepent user "repositories" (one for each user type).
So imho this would be a valid scenario for three STS or a STS with multiple endpoints.
Another way to solve this could be to distinguish the user type by the indentifier of the replying party redirecting the user to the sts. This identifier is submitted in the wtrealm parameter.
The processing sequence could look like the following:
Get configuration for relying party (wtrealm) from configuration store (I'd suggest a database for your rather complex case)
Validate user with username, password and user type (from relying party configuration)
Add claims depending on user type or relying party specific configuration.
The datasbase/class structure for this could look similiar to this:
Need some more information to answer:
Are certain applications only used by certain types of users? Or can any user type access any application? If the former, you can configure the STS for that application to pass that user type as a claim. Each application can be configured to have its own subset of claims.
Where is the user type derived from? If from a repository, could you not simply construct a claim for it?
Update:
#Peter's solution should work.
Wrt. the 3 STS vs. 3 endpoints,
Many STS - can use same standard endpoint with different "code-behind". Would still work if you migrated to an out-the box solution . Extra work for certificate renewals.
One STS - custom endpoints won't be able to be migrated. Only one STS to update for certificate renewals.
Metadata - given that it can be generated dynamically, doesn't really matter. Refer Generating Federation Metadata Dynamically.