API Key/Authorization/Authentication in Open Rasta

151 views
Skip to first unread message

Dave the Ninja

unread,
Oct 22, 2009, 5:23:54 AM10/22/09
to OpenRasta
Hi guys,

I am currently implementing a web API using Open Rasta and things are
going great so far - its an amazing framework to work with!

To give you a bit of background to what I am looking to achieve with
this project, I am creating an API that will return reporting data as
XML or JSON to a number of different front ends (web/phone/app).

The end users can choose between one or all of the front ends to
access the reporting data.

Here is where I am getting confused in the Open Rasta code:

1. The API needs to be secured via an API key, the API key will be
different per front end platform so that I can audit on which platform
is preferred by the end users depending on how many times the API is
accessed using each key. From looking through the code I believe I
need to implement a pipeline contributor to check for the incoming API
key and validate/audit it returning OperationResult.OK/Unauthorised
depending on the result.

2. The API handlers also need to be secured based on a users access
rights/roles. Say, for example, if I have a handler that creates user
accounts. This handler should only be accessible to users with a
SuperUser role. Having looked through the code I see there is an
IAuthenticationProvider interface, but I am really unsure how to
implement this to work with my user account classes**

So here is my question, has anyone implemented anything similar that
could give me pointers on the following aspects:

i. How to authenticate a user via remote call
ii. Restricting handler methods based on role
iii. Using a custom user/role system

** by this I mean that looking in the source code I can see an
implementation of FakeAuthProvider, which seems to be returning a
clear text password to the calling code. I also looked in
DigestAuthorizerContributor and found the following:

var checkHeader = new DigestHeader(authorizeHeader)
{
Password = creds.Password,
Uri = authorizeHeader.Uri
};

I can see that the credentials are being retrieved by
IAuthenicationProvider however I cant seem to see where the password
is being validated against the one that is entered by the user to
authenticate against their username.

Also, I am storing all my passwords against the user as a HASH/Salt so
I can only ever call account.ValidatePassword(passwordUserEntered) to
check if it is valid, and can never get the clear text version back.

Thanks in advance

Dave the Ninja



Dave the Ninja

unread,
Oct 22, 2009, 6:35:34 AM10/22/09
to OpenRasta
One last thing I forgot to mention, I can not use ASP.NET
authentication providers with machine key (for SSO) as the mobile and
desktop apps will not use c# or ASP.NET

I need to implement something that will work across multiple platforms

David

Barry Dahlberg

unread,
Oct 22, 2009, 6:43:27 AM10/22/09
to OpenRasta
I have a pipleline contributor which checks query strings for the key
and either pushes a UserContext into the dependency resolver or
returns an Unauthorised response. I then have an operation
interceptor which runs later and checks that the current UserContext
has permissions for the given handler. I'm using attributes to tag
required permissions on the handlers. You can see part of it in this
thread:

http://groups.google.com/group/openrasta/browse_thread/thread/5d3826107dd960cf

I haven't touched the IAuthenticationProvider at all, I'm not sure if
it was intended to be a general thing or just for the digest auth, Seb?

Dave the Ninja

unread,
Oct 22, 2009, 6:51:54 AM10/22/09
to OpenRasta
Hi Barry

I had a look at your other thread earlier, and I have been hacking
away to figure it out.

Am I correct in assuming Digest Auth is the equivalent of Windows
Authentication?

I like the way it transports the password as MD5 (I think) encrypted
as I am not too keen on passing clear text passwords over http (POST).

I am currently trying to figure out how it validates the password -
however I am starting think I may be chasing ghosts and that your
example is the correct way forward.

David


On Oct 22, 2:43 pm, Barry Dahlberg <barry.dahlb...@gmail.com> wrote:
> I have a pipleline contributor which checks query strings for the key
> and either pushes a UserContext into the dependency resolver or
> returns an Unauthorised response.  I then have an operation
> interceptor which runs later and checks that the current UserContext
> has permissions for the given handler.  I'm using attributes to tag
> required permissions on the handlers.  You can see part of it in this
> thread:
>
>    http://groups.google.com/group/openrasta/browse_thread/thread/5d38261...

Barry Dahlberg

unread,
Oct 22, 2009, 8:31:16 AM10/22/09
to OpenRasta
Digest authentication is an HTTP thing, not Windows:

http://en.wikipedia.org/wiki/Digest_access_authentication

I havent really looked at that part enough to help sorry, my
requirements are a bit different.

Barry

David Lawton

unread,
Oct 22, 2009, 8:43:29 AM10/22/09
to open...@googlegroups.com
Ah so it is what im looking for!

right, back to the drawing board :D

2009/10/22 Barry Dahlberg <barry.d...@gmail.com>



--
"I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." -- Charles Babbage

Sebastien Lambla

unread,
Oct 22, 2009, 11:30:42 AM10/22/09
to open...@googlegroups.com
Yo all,

HTTP digest is the way to send relatively secure (non seeded pwd hashes)
crendentials over HTTP. The problem with digest is that, while it's more
secure than HTTP basic, it stills receives non-seeded pwds. That has two
effects.

First, it's susceptible to dictionary attacks, so only reasonably long
passwords should be used over non-ssl transports.

Second, it requires your db to store the pwd in clear text or the direct
hash, rather than a hash + seed. That means that you need to think that in
case your db gets compromised, finding out the passwords of your user base
is still subject to dictionary attacks. This can be mitigated for by
encrypting the column in sql 2008+, which closes the problem if someone gets
hold of the mdf, but doesn't protect you against sql injection etc.

Digest is still better than Basic, but unless all your pwds are of a
reasonable size, i'd recommend using those over SSL only.

That said, the best way is probably to use your API key as the pwd in digest
auth, and generate such key to be for example hash(pwd+seed) and store that
at user account creation time. That's assuming you're storing only
hash(pwd+seed) and seed in your db.

I'm much less happy with most solutions that require custom http headers for
api keys when http authentication already provides for a combination
username + secret. Add to the fact that every http toolkit out there
supports http authentication, it would be a shame not to use it.

As for windows authentication, you can still use that, but that's IIS
responsibility, not OR.

To answer the remaining question, you currently need to register an
IAuthenticationProvider, and it currently only supports clear-text pwd
storage.

Next version we'll make the authentication system more pluggable, but right
now only digest is supported.

Seb

David Lawton

unread,
Oct 22, 2009, 2:19:38 PM10/22/09
to open...@googlegroups.com
Hi seb thanks for the detailed response. I think I have a more clear
understanding now, and I also believe that digest is more than ample
for what I'm doing as it will be running over https.

I started implementing digest earlier, and believe I am getting close
to getting it running. It hits the iauthentication provider but always
returns a 404. Not sure exactly why as yet but I'll get to the bottom
of it.

Thanks again

David

Sent from my iPhon

David Lawton

unread,
Oct 22, 2009, 3:55:51 PM10/22/09
to open...@googlegroups.com
Hi all

I am picking away at the digest auth just now and i have placed the requires authentication attribute on my handler method for post.

I have also written a concrete implementation fake of IAuthenticationProvider, and have written a test using HttpWebRequest to try and pick away at the digest until I crack it.

I have attached below the code im using for testing and the implementation of IAuthenticationProvider.  My issue is that I can see in fiddler that the headers for the digest authorisation are being set (by OR i believe), but it is always returns a 404.

In the test I am setting the same credentials on the request as are in the fake auth provider.

I have a very strong feeling that I have missed something blatantly obvious.

David

    public class AuthenticationProvider : IAuthenticationProvider 
    {
        public Credentials GetByUsername(string p)
        {
            return new Credentials {Password="P@ssword", Username = "Username"};
        }
    }


    [TestFixture]
    public class Class1
    {
        [Test]
        public void Foo()
        {
            var uri = new Uri("http://localhost/mypostmethod");
            var webRequest = (HttpWebRequest) WebRequest.Create(uri);
            webRequest.Method = "POST";
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";

            var credCache = new CredentialCache();
            credCache.Add(uri, "Digest", new NetworkCredential("Username", "P@ssw0rd"));
            webRequest.Credentials = credCache;

            var postData = HttpUtility.HtmlDecode("FromDate=5%2F20%2F2009&ToDate=10%2F20%2F2009&PagePaths=%2Fpost%2F2008%2F12%2F11%2FHORN-Build-Server-Thank-you-Team-City%21.aspx&PagePaths=%2Fpost%2F2008%2F12%2F21%2FAnyone-need-a-shit-hot-CGIArtistIllustrator.aspx&PagePaths=%2Fpost%2F2009%2F01%2F29%2FMVCNET-RC-Full-Windsor-Stack-with-MVC-Contrib.aspx");
            var byteData = Encoding.UTF8.GetBytes(postData);

            webRequest.ContentLength = byteData.Length;

            using (var stream = webRequest.GetRequestStream())
            {
                stream.Write(byteData, 0, byteData.Length);
            }

            string responseText;
            using (var response = webRequest.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    responseText = reader.ReadToEnd();
                }
            }

            new XmlToObjectLoaderBase<QualifiedVisitorsReport>().Load(responseText);

            Debug.Write(responseText);
        }
    }

------ Test started: Assembly: Web.Specs.dll ------

TestCase 'Web.Specs.Class1.Foo' failed: System.Net.WebException : The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
Class1.cs(43,0): at Web.Specs.Class1.Foo()


0 passed, 1 failed, 0 skipped, took 31.37 seconds (NUnit 2.5.1).


2009/10/22 David Lawton <da...@davetheninja.net>

Sebastien Lambla

unread,
Oct 23, 2009, 1:07:19 AM10/23/09
to open...@googlegroups.com

Does the handler work without authentication enabled?

 

Also, can you post the debug log?

 

Seb

David Lawton

unread,
Oct 23, 2009, 2:07:41 AM10/23/09
to open...@googlegroups.com
Yes it works without the attribute. 

In taxi now so I'll post the debug code when I hit the office. 

Sent from my iPhone

David Lawton

unread,
Oct 23, 2009, 4:05:49 AM10/23/09
to open...@googlegroups.com
I got into the office, rebuilt OR and rebuilt my solution.  Ran my test and it worked. Go figure.

Thanks for all the help guys, I now - hope - I have digest authentication running woop woop!

Now to wire it up to work with the database :D 

Dave the Ninja

2009/10/23 David Lawton <da...@davetheninja.net>
Reply all
Reply to author
Forward
0 new messages