I’m wanting to share an authentication implementation across a web application, and web API. The web application will be ASP.NET (mostly MVC 4), the API will be mostly ASP.NET WEB API, though I anticipate it will also have a few custom modules or handlers.
I want to:
- Share as much authentication implementation between the app and API as possible.
- Have the web application behave like forms authentication (attractive log-in page, logout option, redirect to / from login page when a request requires authentication / authorisation).
- Have API callers use something closer to standard HTTP (401 – Unauthorized, not 302 – Redirect).
- Provide client and server side logout mechanisms that don’t require a change of password (so HTTP basic is out, since clients typically cache their credentials).
The way I’m thinking of implementing this is using plain old ASP.NET forms authentication for the web application, and pushing another module into the stack (much like MADAM – Mixed Authentication Disposition ASP.NET Module). This module will look for some HTTP header (implementation specific) which indicates “caller is API”.
If the header “caller is API” is set, then the service will respond differently than standard ASP.NET forms authentication, it will:
- 401 instead of 302 on a request lacking authentication.
- Look for username + pass in a custom “Login” HTTP header, and return a FormsAuthentication ticket in a custom “FormsAuth” header.
- Look for FormsAuthentication ticket in a custom “FormsAuth” header.
My question(s) are:
- Is there a framework for ASP.NET that already covers this scenario?
- Are there any glaring holes in this proposed implementation? My primary fear is a security risk that I can’t see, but I’m similarly concerned that there may be something about such an implementation that will make it overly restrictive or clumsy to work with.
I don’t quite understand what it is you actually want to share.
I’d assume you won’t find a framework cause what you want to do is not that hard to solve.
1) A third party application is -only- going to touch your general purpose API. It uses API authentication only (through forms authentication, api key usage, take your picking).
2) Your own application through user actions will redirect to login page and such and have it’s own picking of authentication (form authentication probably). This is about stuff the user can potentially enter through the address bar of the webbrowser. If your application happens to use your general purposed API under the hood you are not going to redirect the user to your login page on ajax calls. Your application should handle/prevent this for the user. A user is not going to make API calls through his/her browser’s address bar.
So for your application to be able to use your general purpose API, the general purpose API would only need to support the same authentication scheme (form authentication). Or your application would have to fetch the user’s api key or something to use after the user logged in.
You can easily create an Authorize attribute in MVC that will checks multiple options, first for an api-key, then for a forms authentication based cookie token. If it finds nothing your general purpose API should or needs to throw 401s only.
Your application would pick them up from ajax call failures and could decide to move the user over to the login page.
8
Well, usually this scenario (same server-side system, different clients) is managed delegating to the clients the responsability to use the same service set offered by the server in different ways (In your schema, it is the server that changes its behavour depending on the client request).
In other terms, usually you have:
-
A single API-exposing web server program (usually a webservice, most often a RESTful webservice) that handles all the requests.
-
A web client that asks for the data it needs, creates its own UI and handles all of its interactions with its user and with the server in its specific way. Of course, the UI is generated and managed with Javascript, HTML and CSS (AJAX).
-
An API (no UI) client that asks for the data it needs and handle them in its specific way.
On the server side it is normally used a RESTful webservice because using different HTTP verbs (GET, POST, etc.) it is quite easy to differentiate and satisfy the requests that came from different clients.
Put aside this, it is normally considered a very bad idea to play with custom authentication and security mechanisms/protocols because it is very easy to overlook some important vulnerability. If the main goal of your development effort is NOT the authentication mechanism, you should probably try to use an existing system, like OAuth, CAS or someting like that.
Of course, if the main goal of your development effort IS the authentication mechanism, this does not apply to you. In this second case, you should put in the client request header something that is generated on the server side, is used just to identify the client and is changed very often (that is: a client session ID, most likely a hash) and delegate all of the checks&dance to the server side programs (that is under your control and is trustworthy).
Putting an easy-to-copy, easy-to-forge string into the client request header, and change the server-side software behaviour depending on this string, is not a good way to handle a security-related mechanism like authentication.
4