[ogpx] An Inquiry into the Nature and Causes of Web Capabilities
Infinity Linden <infinity@lindenlab.com> Wed, 03 June 2009 22:41 UTC
Return-Path: <infinity@lindenlab.com>
X-Original-To: ogpx@core3.amsl.com
Delivered-To: ogpx@core3.amsl.com
Received: from localhost (localhost [127.0.0.1]) by core3.amsl.com (Postfix) with ESMTP id B093E3A707B for <ogpx@core3.amsl.com>; Wed, 3 Jun 2009 15:41:58 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.599
X-Spam-Level:
X-Spam-Status: No, score=-1.599 tagged_above=-999 required=5 tests=[AWL=0.378, BAYES_00=-2.599, FM_FORGED_GMAIL=0.622]
Received: from mail.ietf.org ([64.170.98.32]) by localhost (core3.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7wh+iLnAOa0Y for <ogpx@core3.amsl.com>; Wed, 3 Jun 2009 15:41:57 -0700 (PDT)
Received: from an-out-0708.google.com (an-out-0708.google.com [209.85.132.242]) by core3.amsl.com (Postfix) with ESMTP id C84A23A6B76 for <ogpx@ietf.org>; Wed, 3 Jun 2009 15:41:56 -0700 (PDT)
Received: by an-out-0708.google.com with SMTP id c3so218308ana.4 for <ogpx@ietf.org>; Wed, 03 Jun 2009 15:41:52 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.100.210.16 with SMTP id i16mr1738134ang.184.1244068912540; Wed, 03 Jun 2009 15:41:52 -0700 (PDT)
Date: Wed, 03 Jun 2009 15:41:52 -0700
Message-ID: <3a880e2c0906031541n3b1c82a3y5b7c91f20b0eb539@mail.gmail.com>
From: Infinity Linden <infinity@lindenlab.com>
To: "ogpx@ietf.org" <ogpx@ietf.org>
Content-Type: text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding: 7bit
Subject: [ogpx] An Inquiry into the Nature and Causes of Web Capabilities
X-BeenThere: ogpx@ietf.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: Virtual Worlds and the Open Grid Protocol <ogpx.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/listinfo/ogpx>, <mailto:ogpx-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/ogpx>
List-Post: <mailto:ogpx@ietf.org>
List-Help: <mailto:ogpx-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/ogpx>, <mailto:ogpx-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 03 Jun 2009 22:41:58 -0000
So there were a few questions off-line recently about capabilities and their use in OGP. Some people understand them, some people don't. Some people think they're cool, some people want to hurl inanimate objects around at the mention of their name. But it does seem that there's a lot of confusion about the motivation for caps in general and web capabilities in OGP specifically. So i figured i would take a few moments to try to demystify them. 1. What _Are_ Capabilities Anyway? In General, capabilities are authorization tokens designed so that possession of the token implies the authority to perform a specific action. Consider a file handle in POSIX like systems. When you open a file, you get back an integer representing the open file. You only get this file handle back if you have access rights to the file. When you spawn a new child process, the child inherits your open file handles and it too can access those files via the file handle, even though the child process lives in a completely different process space. Later versions of *nix even allow you to move open file handles between unrelated processes. So... the takeaway here is... it's an opaque bit of data (i.e. - a token) and if you have it, it means you have the authority to use it. And... you can pass it around if need be. Capabilities on the web extend the concept. In addition to the token connoting authorization to access some resource, it usually also provides the address to access the resource. In other words, a web capability is a URL possessed by a client that the client may use to create, read, update or delete a resource. A web capabilities in OGP are in the form of a "well known" portion of a URL (something like "http://service.example.org/s/") and a large, unguessable, randomly generated string (like "CE7A3EA0-2948-405D-A699-AA9F6293BDFE".) Putting them together, you get a valid URL a client can use to access a resource via HTTP. In this example, that URL would be "http://service.example.org/s/CE7A3EA0-2948-405D-A699-AA9F6293BDFE". 2. Why the Heck Would I EVER Want to Do THAT !? Yup. No doubt about it, this is not a "standard pattern" for web services. Usually if you have a resource, you publish a well known resource and if it's sensitive you require the client to log in. For example, you might have a RESTful resource at "http://service.example.org/s/group/AWGroupies" that represents the group "AWGroupies". You then define an API that says if you want to post a message to the group, you use HTTP POST with data (XML, JSON or whatever) that implies "post this message to this group". For the sake of discussion, let's say the JSON of the message would look like: { from: "Zha Ewry", message: "I'm giving 50 L$ to anyone who IMs me in the next 5 minutes!" }. This is a perfectly acceptable solution, though readers familiar with AWGroupies will know that i am not, in fact, the first life avatar of Zha Ewry, so i probably shouldn't be posting messages to this group promising to disburse game specie in her name. So authentication is in order, but this is a well known problem, i simply use HTTP digest auth over HTTPS (or something similar) and we're done. This is a perfectly acceptable solution. But there are a couple of issues with this solution. Most notably... every service that presents an interface to a sensitive resource MUST understand authentication. So not only does "http://service.example.org/s/group/AWGroupies" need to understand authentication, so does "http://service.example.org/s/user/Linden/Infinity" and "http://service.example.org/s/parcel/Levenhall/Infinity%20is%20full%20of%stars" and so on. Not a problem really, until you start adding new authentication techniques. So one day your boss comes to you and tells you.. "hey! we're using Secure/IDs for everything now!" Ugh. But it's still not _that_ painful. You've probably abstracted out authentication, so you have a map of service URLs to authentication techniques and common libraries that actually authenticate requests throughout your system. And this works until the day that your boss comes in and says... "hey! we just bought our competitor Cthulhos.Com! we're going to integrate their FooWidget service into our service offering! isn't it great!" And then you get that sinking feeling cause you know that this means you've got to figure a way to get their service to talk to your identity provider so their service can authenticate your customers. People who have been through this know that depending on the technology this can turn out to be a bag full of pain. The standard way of doing this is something like: a. service request come into http://service.example.org/s/foo/Infinity b. http://service.example.org/s/foo/ redirects with a 302 to http://foo.cthulhos.com/Infinity c. http://foo.cthulhos.com/Infinity responds with a 401 getting the client to resubmit the request with a WWW-Authenticate: header. d. the client resubmits to http://foo.cthulhos.com/Infinity with the proper WWW-Authenticate: header, but remember, these are example.org's customers, so e. http://foo.cthulhos.com/Infinity sends a message to a private interface on example.org, asking it to authenticate the user credentials. f. let's assume the client is using valid credentials, so example.org responds to cthulhos.com with the digital equivalent of a thumbs up, and finally... g. http://foo.cthulhos.com/Infinity responds to the request. And this works pretty well up until the point that the new CIO comes in and say.. "infocard! we're moving everything to infocard!" There's nothing wrong with infocard, of course, but i this situation you've got to implement it at both example.org and cthulhos.com. And when we start adding to the mix the fact that the biz dev people keep trying to buy new companies and you get a new CIO every 18 months who wants a new user authentication technology, things can get out of hand. And... i didn't even talk about the fact that each time you change the authentication scheme, thick client developers have to go through the code, looking for every place a request is made. Web Capabilities are not a magic panacea, but they can help out in this situation. Rather than having each request authenticated, the user's identity is authenticated once at a central location and that central location (example.org) coordinates with it's services (cthulhos.com) to provide a unique, unguessable URL (the capability) known only to that specific client and trusted systems (example.org and cthulhos.com). So the flow would be something like... a. client logs in at http://service.example.org/s/authme and asks for a capability to use a particular service b. http://service.example.org/s/authme verifies the user's credentials and verifies the user can access that service c. http://service.example.org/s/authme sends a request to a private interface on cthulhos.com asking for the capability. d. cthulhos.com generates the unguessable capability http://foo.cthulhos.com/EE409B12-6E9B-4F5B-90BF-161AE5DE410C and returns it to http://service.example.org/s/authme e. http://service.example.org/s/authme returns the capability http://foo.cthulhos.com/EE409B12-6E9B-4F5B-90BF-161AE5DE410C to the client f. the client uses the capability http://foo.cthulhos.com/EE409B12-6E9B-4F5B-90BF-161AE5DE410C to access the sensitive resource. Both approaches require establishing a trusted interface between example.org and cthulhos.com, but in the case of the capability example, only service.example.org has to know about the specific details of user authentication. Thick client developers may also notice that they access the capability as if it were a public resource; that is, they don't need to authenticate each request. Another benefit to capabilities is that they are pre-authorized. If you have a resource that is accessed frequently (like maybe "get the next 10 inventory items" or "check to see if there are any messages on the event queue for me") you don't have to do the username -> permissions look up each time the server receives a request. For environments where the server makes a network request for each permissions check, this can lead to reduced request latency. So... to recap... capabilities are not magic panaceas... there's still some work involved in implementing them. and they start making a lot more sense when you have a cluster of machines offering service to a client, but deployers want identity and identity to permissions mapping functions to live elsewhere in the network than the machine offering a service. (i.e. - "the cloud" or "the grid".) 3. Okay... But How Do I Provision a Capability ? I'm sure there are several ways to provision capabilities, but the approach we take in OGP is to use the "seed capability." Like most other distributed protocols involving sensitive resources, OGP protocol interactions begin with user authentication. (This is not strictly true, 'cause i'm ignoring the case where two machines want to communicate outside the context of a user request, but let me hand wave that use case away for the moment while we talk about using seed caps.) The process begins with user authentication. The OGP : Auth specification describes this process; it is essentially the client sending an avatar name and a password to a server in the agent domain. Assuming the authentication request can be validated, the agent domain returns a "seed cap." The client then sends a list of capability names to the seed cap and awaits the response. What the host behind the seed cap is doing while the client waits for a reply is verifying the requested capability exists and the user is permitted to perform the operation implied by the capability. (and it does this for each capability requested.) So, for example, let's say you are a client that only wants to update a user profile and send/receive group messages. The protocol interaction might look something like this... a. authentication : client -> server at https://example.org/login { identifier: { type: "agent", first_name: "Random", last_name: "Avatar" }, authenticator: { type: "hash", algorithm: "md5", secret: "i1J8B0rOmekRn8ydeup6Dg==" } } b. auth response : server -> client { condition: "success", agent_seed_capability: "https://service.example.org/seed/CF577955-3E0D-4299-8D13-F28345D843F3" } c. asking the seed for the other caps : client -> server at https://service.example.org/seed/CF577955-3E0D-4299-8D13-F28345D843F3 { capabilities : [ "profile/update", "groups/search" ] } d. the response with the URIs for the caps : server -> client { capabilities : { profile/update : "http://service.example.org/user/35A59C5D-315C-4D50-B78D-A38D41D2C90A", groups/search : "http://cthulhos.com/8579CE1F-9C05-43E8-8677-A645859DCD64" } } 4. Expiring Capabilities Readers may notice that there is a potential "TOCTOU vulnerability." TOCTOU stands for "time of check, time of use," and refers to a common security problem... what happens if the permissions on an object change between the time the code managing the resource checks the permission and the time it performs an operation on the resource. This is a common problem with many systems, including POSIX file descriptors. (seriously.. if you change the permissions on a file to disallow writing AFTER the file has been opened, subsequent writes on the file descriptor will not fail in many POSIX systems.) OGP capabilities address this problem by expiring capabilities when they get old. So if you request a capability, then wait a LONG time before you access it, you may find that you get a 404 response code. The OGP specifications do not require all caps to expire, but the do require servers to signal their expiration by removing them (thus the 404 response) and require clients to understand what to do when a capability has been expired. In most cases, the appropriate response is to re-request the capability from the seed cap. If the seed cap is expired, clients should re-authenticate. Capabilities may also "expire after first use." Also called "single shot capabilities," they are used to communicate sensitive or highly volatile information to the client. The current practice is to include an Expires: header in the response from the server so the client will know when the resource expires. 5. Introspection on Capabilities Finally, RESTful resources represented by a capability are described by LLIDL, the interface description language used by LLSD. A request has been made that introspection be supported so clients may receive the LLIDL description of a capability and more accurately reason about the semantics of its use. The proposed solution to this problem for OGP messages carried over HTTP is to use the OPTIONS method when accessing the capability (instead of GET, POST, PUT or DELETE.) Upon receipt of the OPTIONS request, the server should respond with the LLIDL describing the resource. 6. Conclusion Capabilities are cool, especially in clouds or grids. 7. References A pair of Google Tech Talks at: http://video.google.com/videoplay?docid=-8527120258517176598 , and http://video.google.com/videoplay?docid=8799856896828158583 provide a pretty good technical introduction to the concept of capabilities. OGP's description of capabilities is at: http://tools.ietf.org/html/draft-lentczner-ogp-base-00#section-2.3 OGP uses capabilities to access RESTful resources. Roy Fielding's paper on REST is at: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
- [ogpx] An Inquiry into the Nature and Causes of W… Infinity Linden
- Re: [ogpx] An Inquiry into the Nature and Causes … Cenji Neutra
- Re: [ogpx] An Inquiry into the Nature and Causes … Hurliman, John
- Re: [ogpx] An Inquiry into the Nature and Causes … Infinity Linden
- Re: [ogpx] An Inquiry into the Nature and Causes … Carlo Wood
- Re: [ogpx] An Inquiry into the Nature and Causes … Cenji Neutra
- Re: [ogpx] An Inquiry into the Nature and Causes … Christian Scholz
- [ogpx] Fwd: An Inquiry into the Nature and Causes… Meadhbh Siobhan
- Re: [ogpx] Fwd: An Inquiry into the Nature and Ca… Nexii Malthus
- [ogpx] SL6B Charles Krinke
- Re: [ogpx] SL6B Infinity Linden