Subject: [OAUTH-WG] Proposal for text for section 2

From: Yaron Goland <[email-masked]>
Date: Fri, 25 Jun 2010 22:32:54 +0000

Motivating Scenario: A client makes a request to a token endpoint. It uses an authorization token to authenticate itself and a refresh token to authenticate it's delegated right. This approach to authenticating clients is used in enterprises all the time because it's good security practice to send values derived from a secret (e.g. an HMAC, digital signature, etc.) rather than the secret itself across the wire, even if the wire is encrypted.

Proposed Text:
2.2  Assertion Client Credentials

The assertion client credentials include a client identifier, assertion and assertion type. If the assertion client credentials are used then the client MUST include the credentials using the following request parameters:

client_id
                REQUIRED. The client identifier.
client_assertion_type
                REQUIRED. The format of the assertion as defined by the authorization server.  The value MUST be an absolute URI.
client_assertion
                REQUIRED. The client assertion.

For example (line breaks are for display purposes only):

                POST /token HTTP/1.1
                Host: server.example.com
                Content-Type: application/x-www-form-urlencoded

                grant_type=refresh_token&client_id=s6BhdRkqt3&
                client_assertion=PHNhbWxwOl...[omitted for brevity]...ZT4%3D&
                client_assertion_type=urn%3Aoasis%3Anames%sAtc%3ASAML%3A2.0%3Aassertion&
                refresh_token=n4E90119d

The client MUST NOT include the client credentials using more than one mechanism. If more than one mechanism is used regardless whether the credentials are identical or valid, the server MUST reply with an HTTP 400 status code (Bad Request) and include the "multiple_credentials" error code.

From: Eran Hammer-Lahav [mailto:[email-masked]]
Sent: Friday, June 25, 2010 11:31 AM
To: Yaron Goland; [email-masked]
Subject: RE: Clients authenticating with assertions

We never had support for two assertions in one request.

The client authenticates itself and can include an assertion (or use type 'none'). The client credentials are the "client assertion" and the assertion is about the resource owner.

Also, you can define an assertion type that's a composite assertion (of one more more).

EHL

From: [email-masked] [mailto:[email-masked]] On Behalf Of Yaron Goland
Sent: Friday, June 25, 2010 11:26 AM
To: [email-masked]
Subject: [OAUTH-WG] Clients authenticating with assertions

If a client wants to authenticate itself to a token endpoint to get an access token using an assertion how should it do it?

Grant_Type = assertion doesn't seem right because that assertion should be from the resource owner who delegated the permission, not from the client, right? In other words one can end up with an access token request with two assertions, one from the client and one from the resource owner. How is this done?

                Thanks,

                                Yaron

P.S. I looked for something like client_assertion and client_assertion_type in section 2 of -08 but didn't see it. Sorry if I missed it.

---

From: Yaron Goland <[email-masked]>
Date: Mon, 28 Jun 2010 21:56:21 +0000

The following is proposed language for a new section, 2.2, in the spec. This is part of the spec that deals with client authentication. This proposal is completely orthogonal to anything in section 4 such as grant types. At Eran's suggestion I added in an example into the text to help readers understand both what the feature is for and how it is used.

Eran also suggested that we should probably introduce a client_cred_type parameter (since we are explicitly support multiple types of client parameters) just to be consistent with grant_type. I don't have strong feelings on the subject and am happy to go with whatever the group wants.

                Thoughts?

                                Thanks,

                                                Yaron

In scenarios where security is at a premium one wants to avoid sending secrets across the Internet, even on encrypted connections. Instead one wants to send values derived from the secret that prove to the receiver that the sender is in possession of the secret without actually sending the secret. Typically the way derived values are created is by generating an assertion that is then either HMAC'd or digitally signed using an agreed upon secret. By validating the HMAC or digital signature on the assertion the receiver of the assertion can prove to themselves that the entity that generated the assertion was in possession of the secret without actually communicating the secret directly.

So, for example, a client can establish a secret using an out of band mechanism with a resource server. As part of this out of band communication the client and resource server agree that the client will authenticate itself using a SAML assertion with agreed upon parameters that will be signed by the provisioned secret.

Later on the client interacts with an end-user and uses the end-user authorization process with the resource server to get an authorization code. The client then sends an access token request to the token endpoint for the resource server and includes, along with the authorization code, a SAML assertion it signed with the previously agreed key and parameters. The SAML assertion proves to the token endpoint the identity of the client and the authorization code provides the link to the end-user authorization. If the access token request comes back with a refresh token then in the future the client can get new access tokens by submitting an access token request containing both a properly signed and formatted SAML assertion as well as the refresh token.

The following defines how to send an assertion as client credentials. If the assertion client credentials are used then the client MUST include the credentials using the following request parameters:

client_id

                POST /token HTTP/1.1
                Host: server.example.com

Token endpoints can differentiate between client assertion credentials and other client credential types by looking for the presence of the client_assertion and client_assertion_type attributes which will only be present with client assertion credentials.

From: [email-masked] [mailto:[email-masked]] On Behalf Of Yaron Goland
Sent: Friday, June 25, 2010 3:33 PM
To: Eran Hammer-Lahav; [email-masked]
Subject: [OAUTH-WG] Proposal for text for section 2

Proposed Text:

client_id

                POST /token HTTP/1.1
                Host: server.example.com

EHL

                Thanks,

                                Yaron

---

From: "Manger, James H" <[email-masked]>
Date: Tue, 29 Jun 2010 14:37:57 +1000

Yaron,

"Assertion Client Credentials" is too much of a hack. It only works for POSTs, and only when the body is form-encoded.

It could not be used, for instance, to delete a token with an HTTP DELETE request to a token URI. Though that specific idea has not been accepted yet, it is a reasonable possibility. We shouldn't introduce a client authentication mechanisms incapable of working with such ideas.

The 1st and 2nd proposed paragraphs are not specific to OAuth at all. The 3rd paragraph mentions authorization codes and refresh tokens, but the client assertion is independent of those. I would prefer to see a standalone description of how to authenticate any HTTP request with a client SAML assertion - then that could apply to the OAuth2 token management API, just as easily as it applies to any other API, and just as easily as any client auth mechanism works with OAuth2.

For instance, why not define a SAML HTTP authentication mechanism:

   Authorization: SAML a=<base64url-encoded SAML assertion>

It is obvious how it can be used to authenticate/authorize client requests to an OAuth2 token endpoint.

It works with GET, HEAD, POST, PUT, DELETE....

It works with XML, JSON, form-encoded... messages.

You don't need special rules about avoiding duplicate authentication mechanisms.

There is a standard way to do discovery: return WWW-Authenticate: SAML realm="Token Management".

Finally, the proposal keeps client_id as a separate parameter. However, I guess that a SAML assertion would often include a client id inside the assertion. This means we have two client ids. At best it is slightly inefficient; it introduces more code paths (eg if they mismatch); at worst it causes security bugs when the "wrong" client id is used at different points in systems.

--

James Manger

From: [email-masked] [mailto:[email-masked]] On Behalf Of Yaron Goland
Sent: Tuesday, 29 June 2010 7:56 AM
To: Eran Hammer-Lahav; [email-masked]
Subject: Re: [OAUTH-WG] Proposal for text for section 2

                Thoughts?

                                Thanks,

                                                Yaron

client_id

client_assertion_type

client_assertion

                POST /token HTTP/1.1

                Host: server.example.com

                refresh_token=n4E90119d

---

From: Marius Scurtescu <[email-masked]>
Date: Tue, 29 Jun 2010 09:58:34 -0700

>    Authorization: SAML a=<base64url-encoded SAML assertion>

This came up in another thread, but SAML assertions could be too large
to be passed through an HTTP header. Other than that, your suggestion
really simplifies things.

Marius

---

From: Yaron Goland <[email-masked]>
Date: Tue, 29 Jun 2010 19:17:32 +0000

SAML assertions routinely run into the 10s and even 100s of K. This exceeds the practical limit that most HTTP servers and proxies put on the size of the HTTP request headers they are willing to accept. So we cannot rely on the HTTP authorization header as a means of transporting SAML assertions. We are thus, as a practical matter, forced into using the request body.

From: Manger, James H [mailto:[email-masked]]
Sent: Monday, June 28, 2010 9:38 PM
To: Yaron Goland; [email-masked]
Subject: RE: Proposal for text for section 2

Yaron,

--
James Manger

                Thoughts?

                                Thanks,

                                                Yaron

client_id

                POST /token HTTP/1.1
                Host: server.example.com

---

From: "Manger, James H" <[email-masked]>
Date: Wed, 30 Jun 2010 10:07:34 +1000

Marius,

> really simplifies things.

What are the limits on HTTP headers?
I don't think there are any in the HTTP spec.
<http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-09#section-3.2>
A comment in the other thread said SPNEGO headers can be up to 12392 bytes and do not seem to be a problem.
<http://www.ietf.org/mail-archive/web/oauth/current/msg03359.html>

I is hard to support a POST-and-form-only method when there is an alternative that "really simplifies things" without more concrete information on what the actual HTTP limits are (& how hard it is to increase them), and what practical assertion sizes are.

--
James Manger

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Tue, 29 Jun 2010 17:14:30 -0700

More precisely, what are the actual deployed limits on HTTP *request* headers in popular HTTP servers like Apache and IIS, and in popular client platform likely to use this size assertions?

EHL

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf
> Of Manger, James H
> Sent: Tuesday, June 29, 2010 5:08 PM
> To: Marius Scurtescu
> Cc: [email-masked]
> I is hard to support a POST-and-form-only method when there is an
> alternative that "really simplifies things" without more concrete information
> on what the actual HTTP limits are (& how hard it is to increase them), and
> what practical assertion sizes are.
> 
> 
> --
> James Manger
> _______________________________________________
> OAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/oauth

---

From: "Manger, James H" <[email-masked]>
Date: Wed, 30 Jun 2010 12:29:31 +1000

Yaron,

[Sorry I didn't see your response before sending my previous reply]

> SAML assertions routinely run into the 10s and even 100s of K.
> This exceeds the practical limit that most HTTP servers and proxies
> put on the size of the HTTP request headers they are willing to accept.
> So we cannot rely on the HTTP authorization header
> as a means of transporting SAML assertions.
> We are thus, as a practical matter, forced into using the request body.

So SAML assertions are impractical for authenticating/authorizing requests to a general HTTP API. Three options are:
1) Swap the assertion for session credentials that work with the API; or
2) Redefine the API to include the client assertion, which constrains the API to only use POSTs of form-encoded requests; or
3) Shrink the assertions (eg with compression or an artefact-binding) so it fits the HTTP model.

The API in question here is the OAuth2 "token endpoint" API [section 4 of draft-ietf-oauth-v2-09].
You want to take option 2 -- which sort of makes sense in this case since this API is already about swapping credentials.

This feels like a good candidate for a separate spec: "An HTTP API for obtaining an OAuth2 token with an assertion".

The proposal might jar a little less if it was part of the API definition [section 4]. It is certainly not "completely orthogonal to anything in section 4" since it adds constraints (POST and form-encoding) and applies only to the specific section 4 API and no others.

--
James Manger

..."Assertion Client Credentials" is too much of a hack. It only works for POSTs, and only when the body is form-encoded.

It could not be used, for instance, to delete a token with an HTTP DELETE request...

The following is proposed language for a new section, 2.2, in the spec. This is part of the spec that deals with client authentication. This proposal is completely orthogonal to anything in section 4 such as grant types...

...

---

From: Kris Selden <[email-masked]>
Date: Tue, 29 Jun 2010 20:17:58 -0700

This is configurable in IIS, Apache and Nginx but the default ranges from 4k to 16k.

Don't know if there are issues with buffer sizes on the client side.

---

From: Yaron Goland <[email-masked]>
Date: Thu, 1 Jul 2010 00:47:44 +0000

James, how can you ding client assertions credentials for doing exactly what client basic credentials do?

The current spec defines that client basic credentials can go into the request body and defines this behavior in section 2. I just patterned the client assertion credentials text word for word from the existing basic credentials text.

That having been said I wonder if there isn't a simple compromise here. How about we edit the client assertion proposal to include the ability to put assertions both in the HTTP authorization header as well as in the body? Then the assertion proposal will be 100% equivalent to the existing basic credentials proposal.

After all, if we do have an assertion that is small enough to fit in the header I'd rather see it there than in the body. I personally only want the body as an emergency escape hatch. I'm certainly no fan of shoving this kind of stuff in the request body.

	What do you think?

		Yaron

> Sent: Tuesday, June 29, 2010 7:30 PM
> > So we cannot rely on the HTTP authorization header as a means of
> > transporting SAML assertions.
> 2) Redefine the API to include the client assertion, which constrains the API
> to only use POSTs of form-encoded requests; or
> You want to take option 2 -- which sort of makes sense in this case since this
> API is already about swapping credentials.
> 
> This feels like a good candidate for a separate spec: "An HTTP API for
> obtaining an OAuth2 token with an assertion".
> 
> The proposal might jar a little less if it was part of the API definition [section
> 4]. It is certainly not "completely orthogonal to anything in section 4" since it
> adds constraints (POST and form-encoding) and applies only to the specific
> section 4 API and no others.
> 
> --
> James Manger
> 
> 
> 
> ..."Assertion Client Credentials" is too much of a hack. It only works for
> POSTs, and only when the body is form-encoded.
> 
> Of Yaron Goland
> The following is proposed language for a new section, 2.2, in the spec. This is
> part of the spec that deals with client authentication. This proposal is
> completely orthogonal to anything in section 4 such as grant types...
>

---

From: "Manger, James H" <[email-masked]>
Date: Thu, 1 Jul 2010 14:18:19 +1000

Yaron,

> how can you ding client assertions credentials for doing exactly what client basic credentials do?

I don't like client basic credentials in request bodies either. We should ditch that as well. I am sure I have dinged it in the past. It offers too little benefit for the cost of confusing APIs (& code) by mixing the content and authentication. And you lose a well-established discovery method: a response with WWW-Authenticate: BASIC ....

At least with basic credentials they can fit in a URI. Consequently, they don't prevent GET, HEAD, or DELETE requests, or even non-form PUT and POST requests in an API. Plus the Authorization header equivalent approach always works as well.
[You can almost consider an "endpoint with client_id and client_secret" as a single base URI for the API -- and almost pretend that it doesn't compromise the HTTP model.]

> How about we edit the client assertion proposal to include the ability to put assertions both in the HTTP authorization header as well as in the body? Then the assertion proposal will be 100% equivalent to the existing basic credentials proposal.

It is hardly 100% equivalent when the header option will fail in some cases (large assertions), and the other option fails for GETs, HEADs, DELETEs, and non-form requests.

I would like OAuth2 to say: "The token API will often require client auth; a service MAY support any auth mechanisms; BASIC is a recommended mechanism; BASIC MUST be supported if the service issues shared secrets to clients".
Using a client assertion would fit right in if it could be defined as a standalone HTTP auth mechanism (even with a option to use form params for POSTs of forms). This would be best as its own standalone spec.

If such a spec gets support (despite sometimes failing for non-POST or non-form requests), we are done. If such a spec isn't supported it suggests we should define a specific API that accepts client assertions, instead of an "orthogonal" auth mechanism (still best in its own spec).

P.S. When are client_assertion/client_assertion_type used, as opposed to assertion/assertion_type? It is not clear to me from the existing and proposed spec text. I don't think the OAuth2 spec has enough context for the assertion parts. It would be better outside the OAuth2 spec, where more details could be provided about how it hooks up with the rest of a claims-based system.

--
James Manger

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Wed, 30 Jun 2010 21:51:04 -0700

> Sent: Wednesday, June 30, 2010 9:18 PM
> I don't like client basic credentials in request bodies either. We should ditch
> that as well. I am sure I have dinged it in the past. It offers too little benefit
> for the cost of confusing APIs (& code) by mixing the content and
> authentication. And you lose a well-established discovery method: a
> response with WWW-Authenticate: BASIC ....

You can still do that. The client_id and client_secret parameters are nothing more than a convenient tool for the most common use case. Also, if you noticed, Basic is not the primary method and the parameters are secondary. That's as far as consensus allowed and I would like to consider this item closed.

EHL