Martin,
great to see you contributing to the WG!
One question came into my mind: How do the other grant types (assertion,
username/password, refresh token) fit into your abstractions? The grant
type used also depends on the client and its capabilities, so just
returning a single URL pointing to an access token resource might not be
suffice.
To give an example:
Alice stores her contacts at contacts.example.com.
She uses 2 clients, one on the PC and one on a mobile phone. The PC
client uses the standard redirect-based process. The mobile phone client
cannot use this process because of technical limitations (small screen
size, sparse computing power, no integration API for embedding the
browser or custom schemes). Therefore this client uses the
username/password flow in order to get authorization and obtain a
refresh token. The implications with respect to the flow:
PC client: redirect to end-user authorization endpoint
Mobile phone client: access to the tokens endpoint with the user's
credentials
So although the resource server's URL is the same in both cases,
different URLs will be utilized to process the authorization flow.
regards,
Torsten.
Am 22.10.2010 00:36, schrieb Thomson, Martin:
At the last meeting, I promised Blaine that I'd share a few thoughts on how I
understood OAuth to operate. It's taken me a while to find the time to marshal
my thoughts, but here 'tis.
After attending the meeting and tutorial, it was clear that the abstraction
behind OAuth is not being effectively communicated. A simple abstraction can
be a powerful tool in dealing with a complex specification. It seems to me
that OAuth struggles as a result of trying to cover so many use cases at once.
This might be easier if the abstract model were better understood.
I believe that OAuth has a very simple abstraction. What I am going to try to
do is describe that abstraction.
The cunning techniques employed to circumvent technical limitations -
redirection with URI fragments and so forth - are noise on the wire at this
layer. As a necessary product of having to reduce the abstraction to practice,
they have little bearing on what I am going to attempt to describe.
I appreciate that the process is well beyond this airy-fairy stage. If nothing
else, I hope that this jostles a few brain cells into new ways of looking at
OAuth.
To preface this with a warning: There's been a lot of discussion about the OAuth
"protocol" and examination of its properties from the perspective of it being a thing
that "uses HTTP". There's a lot of HTTP experience that teaches the long term folly of
trying to build on top of HTTP. I'm probably going to beat on a dead horse by explaining where
working _with_ HTTP (as opposed to _despite_ it) has significant advantages.
==First Abstraction
OAuth specifies a separation between authentication and authorization.
Never mind that HTTP got these mixed up early on, it doesn't now - HTTP only provides
authentication. The "Authorization" header is for authentication. That might
be implicitly used to infer authorization, but it's still fundamentally just
authentication.
OAuth lets a Client come to a Resource Server with separate evidence for
identity and authorization.
==Goal
A Client's goal is to acquire a resource from the Resource Server. Or, to be
more general, to successfully complete a particular type of (HTTP) request.
In order to do this, authentication is not sufficient, the Client must also
prove that it is authorized.
The Client might be known to the Resource Server. This is the authentication
part. There are existing mechanisms for that (the idea that these might be
improved is a subject that comes up on occasion). [1]
==Proving Authorization
Once the Client is authenticated (or not) the Resource Server might still
reject the request. There's an HTTP 403 (Forbidden) response for this purpose.
If this were at all like an HTTP 401 response, that rejection could provide the
clues that could be used by the Client to determine how to acquire evidence of
authorization (what OAuth calls the Access Token).
I don't know if anyone has proposed this, but it seems logical to extend HTTP
and work within its framework, thus:
1. Add a header to the 403 (Forbidden) response. This header would indicate
that irrespective of the identity of the client, further evidence of
authorization is required (that is, an Access Token).
2. Add a request header that is intended to carry an access token.
The first might be a little complex. Unlike the 401 response, OAuth has a
number of variations on how an Access Token is required and this constrains the
information that can be revealed at this point.
This 403 header might include virtually no clues at all. Maybe the equivalent of
"realm" - some private identifier that helps those in the know distinguish
between one set of authorization requirements from another. What information is revealed
depends on the desired security properties.
==Access Token
It's tempting to say that the Access Token is completely opaque to all but the
Authorization Server and the Resource Server. A private agreement between
these parties could be used to determine what information is included.
In the abstract sense, the definition of the request header could just provide
a bit bucket for a token. In the macro, that's all the solution requires.
Obviously, the work doesn't stop there. To ignore the access token entirely
would be trivializing all the work that has been done in this area. A separate
authorization function is an important feature. Structured agreements, such as
the SAML assertions, have a significant role and formalizing formats can be
extremely powerful.
Then there are the security concerns that arise when you wave your hands. Saying
"magic happens here" means that people create their own magic. And that never
really works out well.
So define two things:
- how to acquire an access token
- what the access token looks like, what data it contains, necessary bindings
and so forth
The access token format is where you get into signatures and the like. It also
depends a lot on what the use cases are and the security properties that you
desire. I'm going to concentrate on the acquisition thing first and foremost.
The format should follow from that.
==Acquiring an Access Token
If the Access Token is view as an opaque lump of data [2], then there's an HTTP
method that's well suited to this task: GET.
GET goes a surprisingly long way to accomplishing this task.
Say that the 403 response included - in the responses header, maybe a Link
header - a URI. That URI could be the URI for an Access Token resource.
Require authentication of the Client in order to successfully acquire the
contents of this resource and you have dealt with the basic scenarios shown in
Figures 2 and 3 of the -10 version of the spec.
This URI might not directly refer to the Access Token resource. It could lead
to a chain of HTML pages that need to be navigated successfully to get to the
token.
The same basic abstraction also applies to the Access Grant. The Access Grant
and Access Token share a surprising number of common characteristics. They
both carry authorization information, independent of authentication. The only
difference is where they are acquired from. An Access Grant is an Access Token
for the Access Token resource. Both are optional: the only difference being
that if you don't use an Access Token, you aren't using OAuth.
What if the Access Grant and Access Token used the same mechanism? Then you
just have a chaining of the same process:
Client goes to Resource Server, gets 403, 403 points to Authorization Server
Client goes to Authorization Server, gets 403, 403 points to Resource Owner
Client goes to Resource Owner, gets Access Token A (an Access Grant).
Client takes Access Token A to Authorization Server with Access Token A,
gets Access Token B
Client takes Access Token B to Resource Server, gets resource
You could see how this could recurse.
(It also occurs that you could also parallelize the process too and require multiple
Access Tokens. The analogy would be something like: "you must first collect the
sword of Knorr, the sceptre of Manoth and the crown of Zaxx before you can claim the
throne of Orion". I don't know if this fits into the existing model at all, or even
if it makes sense at all.)
==Other Stuff: Crazy Out of Band Ideas
That's really the core of the idea that I had, but there are a few things that
I think are worth considering.
Implicit in my description is the fact that the entity that demands an Access
Token (Resource Server, Authz Server) needs to know about the entity that
produces it (Authz Server, Resource Owner). I don't think that this is an
unreasonable constraint. The consumer of the Access Token has to know who
produced it to check whether or not the Token can be trusted enough.
That could be used to push a number of things out of scope for the
specification. (Again, with due caution regarding the security properties - it
might still be necessary to describe these uses, even if the on-the-wire
formats aren't defined. On-the-wire formats might still be part of external
work.)
A lot of specification goes into specifying the things that are being exchanged
between Resource Server and Authorization Server. These could almost all be
deferred to other specifications or only talked about from the security
perspective.
For instance, the current request for an Access Token includes a client_id.
The reason for this is to ensure that the Access Token is correctly bound to a
specific Client - so that another client can't use the token [3]. When it is
assumed that the Resource Owner knows about the Authz Server, we can also
assume that the Resource Owner is able to direct the Client to the Authz Server
so that the Access Token it produces has the necessary bindings.
Another example is the redirect. If the client follows the link to the
Authorization Server, a Referrer header might be observed by the Authorization
Server. Once the Authorization interaction is complete, the Authorization
Server could redirect back to the URI it first saw. Alternatively, this
information might be buried in the URI with the other junk, as described above.
There's no need to formalize this mechanism if the agreement is private.
E.g.
Client goes to Resource Server, gets 403 response. The 403 contains a URI
that, along with identifying the Authorization Server, includes in an opaque
portion that contains additional information: the client identity, the resource
the client is trying to access, and other constraints. The Resource Server
knows how to construct this URI so that the Authorization Server can make sense
of this. By navigating to this resource, the Client ultimately acquires an
Access Token - probably some sort of document with a media type that identifies
it as an Access Token.
Client brings the Access Token back to the Resource Server. The Resource
Server cracks that token open and checks it: is it valid? is it from an
Authorization Server that I trust? is it for the current resource? is it for
the current requester? is it valid right now? If a check fails, the request is
rejected; if they all pass, the request is permitted.
Formalizing the exchange between Resource Server and Authorization Server lets
an arbitrary Resource Server use an arbitrary Authorization Server. There are
good use cases for this, but they are secondary to the function I describe
above. Separating that makes a great deal of sense.
==Other Stuff: Slightly Wacky Ideas
What if the resource that provides the Access Token provided the Access Token
to any and all who asked? That's not unreasonable if the token can only be
used by an authenticated Client.
If the resource didn't exist until the Client was authorized, then that would
make this more effective.
Or, maybe better yet, the resource might exist anyway, but the Client isn't
told about the resource until they are authorized. Anyone that knows the URI
can use it freely, but only the authorized are ever granted knowledge of the
URI. The only condition is that the URI is hard to guess. (See RFC5808 for a
different application of this concept and a discussion of the limitations. I'm
also aware that this might have other issues in a web environment, because URIs
don't stay secret with Referrer headers and the like.)
In this model, the URI and Access Token are interchangeable. If you have the
URI, you can give it to someone and that's just as good as giving them a token.
This might be useful for some of the more extreme use cases.
==No-so-thin Client
A lot of focus has been placed on using a client that doesn't understand OAuth
for each of the use cases. The use of redirection, particularly with URI
fragments, belies this. None of what I've suggested is impossible, it just
requires that the Client have some control over the content of the HTTP
requests that it makes.
That doesn't require explicit support from an HTTP client, just the ability to
make requests and set the content of headers. Such support has been table
stakes for a long time.
Regards,
Martin
[1] Note that authentication is not strictly necessary, it might be sufficient
to provide evidence of authorization as described in the counter-examples here:
http://arstechnica.com/security/guides/2010/09/twitter-a-case-study-on-how-to-do-oauth-wrong.ars/2
[2] Copious caveats - as I mentioned, treating the Access Token as an opaque
blob is merely a useful abstraction. It gets you a long way. Before you have
to worry about specifics you can understand a lot about the goals and how those
goals are achieved.
[3] It's interesting that the Access Token producer doesn't need to validate
the client identifier. As long as they aren't duped about who they are
producing the Access Token for, they don't care that the entity that is asking
is the same or not - only the consumer of the token needs to check that it is
OK.
_______________________________________________
OAuth mailing list
OAuth@ietf.org
https://www.ietf.org/mailman/listinfo/oauth
_______________________________________________
OAuth mailing list
OAuth@ietf.org
https://www.ietf.org/mailman/listinfo/oauth