git-svn-id: file:///home/ksmith/gitmigration/svn/xmpp/trunk@2141 4b5297f7-1745-476d-ba37-a9c6900126ab
This commit is contained in:
Peter Saint-Andre 2008-08-07 18:05:26 +00:00
parent dddcf74579
commit 95d68854ca
1 changed files with 123 additions and 241 deletions

View File

@ -6,8 +6,8 @@
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Authorization Tokens</title>
<abstract>This specification defines an XMPP extension for generating, requesting, and using authorization tokens, which can be used to join Multi-User Chat rooms, subscribe to Publish-Subscribe nodes, and even register XMPP accounts.</abstract>
<title>OAuth Over XMPP</title>
<abstract>This specification defines an XMPP extension for delegating access to protected resources over XMPP, using the OAuth protocol. In the language of OAuth, a User can authorize a Consumer to access a Protected Resource that is hosted by a Service Provider; this authorization is encapsulated in a token that the User requests from the Service Provider, that the User shares with the Consumer, and that the Consumer then presents to the Service Provider. This specification assumes that OAuth tokens will be acquired via HTTP as defined in the core OAuth specification, then presented over XMPP to a Service Provider. The Protected Resources accessible over XMPP might include groupchat rooms, data feeds hosted at publish-subscribe nodes, media relays, communication gateways, and other items of interest.</abstract>
&LEGALNOTICE;
<number>0235</number>
<status>Experimental</status>
@ -19,8 +19,14 @@
</dependencies>
<supersedes/>
<supersededby/>
<shortname>NOT YET ASSIGNED</shortname>
<shortname>NOT_YET_ASSIGNED</shortname>
&stpeter;
<revision>
<version>0.4</version>
<date>2008-08-07</date>
<initials>psa</initials>
<remark><p>Incorporated consensus reached at XMPP Summit #5: specified that HTTP is used except for presentation of an Access Token, corrected signature generation algorithm, specified security considerations, and removed invitation and account registration use cases.</p></remark>
</revision>
<revision>
<version>0.3</version>
<date>2008-03-31</date>
@ -46,280 +52,156 @@
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>Although authentication is required in order to access an XMPP network, in some situations it is desirable to require authorization in order to access certain entities on the network. For example, authorization may be required in order to join a &xep0045; room or to subscribe to a &xep0060; node. This document defines a general method for obtaining, sharing, and using authorization tokens over XMPP.</p>
<p>Although authentication is required in order to access the XMPP network, in some situations it is desirable to require authorization in order for an authenticated entity to access certain resources on the network. For example, authorization may be required to join a &xep0045; room, subscribe to a &xep0060; node, or to access other resources of interest (such as a media relay or communications gateway).</p>
<p>Dedicated technologies exist for authorization. One such technology is &oauth;, as defined at &lt;<link url='http://oauth.net/core/1.0/'>http://oauth.net/core/1.0/</link>&gt;. In the language of OAuth, a User can authorize a Consumer to access a Protected Resource that is hosted by a Service Provider; this authorization is encapsulated in a token that the User requests from the Service Provider, that the User shares with the Consumer, and that the Consumer then presents to the Service Provider.</p>
<p>This specification assumes that OAuth Access Tokens will be acquired outside the XMPP (i.e., via HTTP as defined in the core OAuth specification) and merely presented over XMPP.</p>
</section1>
<section1 topic='Obtaining an Authorization Token' anchor='obtain'>
<p>In order to obtain an authorization token that can be sent to a consumer, a user requests an authorization token from the relevant service. For example, let us imagine that the user &lt;crone1@shakespeare.lit&gt; wishes to invite the consumer &lt;hecate@shakespeare.lit&gt; to the chatroom &lt;darkcave@macbeth.shakespeare.lit&gt;. Assuming that the user has already determined that the chatroom supports authorization tokens, the user would send the following request to the room &NSNOTE;.</p>
<example caption='Token request'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
id='request1'
to='darkcave@macbeth.shakespeare.lit'
type='get'>
<token xmlns='urn:xmpp:tmp:auth-token'
consumer='xmpp:hecate@shakespeare.lit'/>
</iq>
]]></example>
<p>If the room supports authorization tokens and the user is allowed to invite contacts to the room, the room returns an authorization token to the user.</p>
<example caption='Token response'><![CDATA[
<iq from='darkcave@macbeth.shakespeare.lit'
id='request1'
to='crone1@shakespeare.lit/desktop'
type='result'>
<token xmlns='urn:xmpp:tmp:auth-token'
consumer='xmpp:hecate@shakespeare.lit'
expires='2007-02-21T23:59:59Z'
service='darkcave@macbeth.shakespeare.lit'>
37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643
</token>
</iq>
]]></example>
<p>The syntax of the &lt;token/&gt; element is as follows.</p>
<ul>
<li>The OPTIONAL 'expires' attribute defines a date and time when the token expires. If included, it MUST be a DateTime as specified in &xep0082;.</li>
<li>The REQUIRED 'consumer' attribute defines the URI of the entity to be authorized (e.g., an XMPP URI, mailto URI, or HTTP URL).</li>
<li>The REQUIRED 'service' attribute defines the JabberID of the service for which the consumer is being authorized.</li>
<li>The OPTIONAL 'node' attribute defines a publish-subscribe node at the service; if the 'node' attribute is included, the authorization MUST be accepted only for interactions with that particular node.</li>
<li>The XML character data of the &lt;token/&gt; element is the authorization token itself.</li>
</ul>
</section1>
<section1 topic='Generating an Authorization Token' anchor='generate'>
<p>A service MAY use any algorithm in generating an authorization token. Depending on implementation and deployment policies, the algorithm MAY take into account the URI of the consumer and be limited to use by an entity that communicates via that URI. Acceptable algorithms MAY include those defined by other standards development organizations, such as &oauth;.</p>
</section1>
<section1 topic='Sharing an Authorization Token' anchor='share'>
<p>The user can then send the authorization token to the consumer in an XMPP message stanza:</p>
<example caption='Sharing the authorization token'><![CDATA[
<message from='crone1@shakespeare.lit/desktop' to='hecate@shakespeare.lit'>
<token xmlns='urn:xmpp:tmp:auth-token'
consumer='xmpp:hecate@shakespeare.lit'
expires='2007-02-21T23:59:59Z'
service='darkcave@macbeth.shakespeare.lit'>
37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643
</token>
</message>
]]></example>
</section1>
<section1 topic='Using an Authorization Token' anchor='use'>
<p>If the consumer wishes to use the token, it MUST first determine the identity of the service (via &xep0030;) so that it can decide how to proceed.</p>
<p>Note: If the service supports this protocol, it MUST return a service discovery feature of "urn:xmpp:tmp:auth-token" in response to each disco#info request (see the <link url='#support'>Determining Support</link> section of this document).</p>
<section2 topic='Multi-User Chat' anchor='use-muc'>
<p>In this example, the service is a multi-user chat service. If authorization is required in order to join a particular room but the joining entity does not include an authorization token in its join request, the service MUST return an error as follows.</p>
<example caption='Chatroom join without token'><![CDATA[
<presence from='hecate@shakespeare.lit/broom' to='darkcave@macbeth.shakespeare.lit/Hecate'/>
]]></example>
<example caption='Error from chatroom'><![CDATA[
<presence from='darkcave@macbeth.shakespeare.lit/Hecate'
to='hecate@shakespeare.lit/broom'
type='error'>
<error type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
<token-required xmlns='urn:xmpp:tmp:auth-token'/>
</error>
</presence>
]]></example>
<p>The consumer would then include the authorization token in its join request.</p>
<example caption='Chatroom join with token'><![CDATA[
<presence from='hecate@shakespeare.lit/broom' to='darkcave@macbeth.shakespeare.lit/Hecate'>
<token xmlns='urn:xmpp:tmp:auth-token'>
37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643
</token>
</presence>
]]></example>
<p>If the token is acceptable, the service will then allow the consumer to enter the room.</p>
<p>Note: Although <cite>XEP-0045</cite> includes a protocol for inviting a contact to a chatroom, that protocol results in the sending of an invitation from the chatroom to the contact (a "mediated invitation"), not from the inviting user to the contact (a "direct invitation"). Because use of &xep0016; may result in blocking of XML stanzas from entities that are not in the contact's roster, mediated invitations may never be delivered to the contact. Use of authorization tokens as described herein enables a user to directly send an invitation to a contact, thus routing around the blocking of mediated invitations.</p>
</section2>
<section2 topic='Publish-Subscribe' anchor='use-pubsub'>
<p>In this example, the service is a publish-subscribe service. If authorization is required in order to subscribe to a particular node but the subscribing entity does not include an authorization token in its subscribe request, the service MUST return an error as follows.</p>
<example caption='Subscription request without token'><![CDATA[
<section1 topic='Protocol Flow' anchor='flow'>
<p>The typical scenario is for a Consumer to request the authorization to act as a delegated authority on behalf of the User to access a Protected Resource owned by the User at a Service Provider. For example, the owner of a pubsub node could allow a remote entity to publish to that node (the single lines show protocol flows over HTTP and the double lines show protocol flows over XMPP):</p>
<code><![CDATA[
Consumer Service Provider
| |
| request a Request Token |
|---------------------------->|
| grant the Request Token |
|<----------------------------|
| |
| [Consumer redirects User |
| to Service Provider] |
| |
| request an Access Token |
|---------------------------->|
| grant the Access Token |
|<----------------------------|
| access Protected Resource |
|============================>|
| |
]]></code>
<p>Before presenting an access token to a Service Provider via XMPP, a Consumer SHOULD verify that the Service Provider supports this protocol, as described under the <link url='#support'>Determining Support</link> section of this document.</p>
<p>Consider the example of a User (say, &lt;world-traveler@example.com&gt;) who wishes to authorize a Consumer (say, an application called FindMeNow as represented by the JID &lt;travelbot@findemenow.tld&gt;) to access the User's geolocation feed at a Service Provider called WorldGPS (as represented by a publish-subscribe node of &lt;feeds.worldgps.tld/world-traveler&gt;). The order of events might be as follows.</p>
<ol start='1'>
<li>WorldGPS and FindMeNow have agreed upon a certificate and secret for FindMeNow to use when communicating with WorldGPS.</li>
<li>WorldGPS maintains a feed for the User's location data in an XMPP PubSub Node.</li>
<li>The User visits FindMeNow.tld and requests real-time updates from his WorldGPS feed.</li>
<li>FindMeNow, over HTTP, requests a "request token" from WorldGPS's pubsub service, signing it with the agreed-upon certificate and secret.</li>
<li>WorldGPS, if the signature was valid, sends FindMeNow a "request token."</li>
<li>FindMeNow then redirects the user to a WorldGPS webpage.</li>
<li>On the WorldGPS webpage, the User logs in (or is already logged in) and is then asked whether to approve of FindMeNow having read-only access to his geolocation information.</li>
<li>The User approves the request and WorldGPS redirects the User back to FindMeNow.</li>
<li>FindMeNow, over HTTP, requests an "access token" (again signing it) and now using the "request token" approved by the User.</li>
<li>WorldGPS, if the signature is correct and the request token was approved, replies with an access token.</li>
<li>FindMeNow, over XMPP, subscribes to the User's pubsub node using the access token.</li>
</ol>
<p>As a result, FindMeNow gets updated every time the User publishes items to his geolocation node at WorldGPS.</p>
<p>Steps 1 through 10 occur via HTTP. Step 11 would be represented in XMPP as follows.</p>
<example caption='Pubsub subscription request with token'><![CDATA[
<iq type='set'
from='notify.marlowe.lit'
to='pubsub.shakespeare.lit'
from='travelbot@findmenow.tld/bot'
to='feeds.worldgps.tld'
id='sub1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscribe node='bard_geoloc'/>
<oauth xmlns='urn:xmpp:tmp:oauth'>
<oauth_consumer_key>0685bd9184jfhq22</oauth_consumer_key>
<oauth_token>ad180jjd733klru7</oauth_token>
<oauth_signature_method>HMAC-SHA1</oauth_signature_method>
<oauth_signature>wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D</oauth_signature>
</oauth>
</pubsub>
</iq>
]]></example>
<example caption='Error from node'><![CDATA[
<iq type='error'
from='pubsub.shakespeare.lit'
to='notify.marlowe.lit'
id='sub1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscribe node='bard_geoloc'/>
</pubsub>
<error type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
<token-required xmlns='urn:xmpp:tmp:auth-token'/>
</error>
</iq>
]]></example>
<p>The contact would then include the authorization token in its subscription request.</p>
<example caption='Subscription request with token'><![CDATA[
<iq type='set'
from='notify.marlowe.lit'
to='pubsub.shakespeare.lit'
id='sub1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscribe node='bard_geoloc'/>
<token xmlns='urn:xmpp:tmp:auth-token'>
37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643
</token>
</pubsub>
</iq>
]]></example>
<p>If the token is acceptable, the service will then allow the consumer to subscribe to the node.</p>
</section2>
<section2 topic='Account Registration' anchor='use-register'>
<p>In this example, the service allows new account registration using &xep0077;. The registering entity SHOULD request the registration form before attempting to register.</p>
<example caption='Consumer requests registration form'><![CDATA[
<iq type='get'
to='contests.shakespeare.lit'
id='reg1'>
<query xmlns='jabber:iq:register'/>
</iq>
]]></example>
<example caption='Host returns registration form'><![CDATA[
<iq type='result'
from='contests.shakespeare.lit'
to='juliet@capulet.com/balcony'
id='reg1'>
<query xmlns='jabber:iq:register'>
<instructions>
Use the enclosed form to register. If your Jabber client does not
support Data Forms, visit http://www.shakespeare.lit/contests.php
</instructions>
<x xmlns='jabber:x:data' type='form'>
<title>Contest Registration</title>
<instructions>
Please provide the following information
to sign up for our special contests!
</instructions>
<field type='hidden' var='FORM_TYPE'>
<value>jabber:iq:register</value>
</field>
<field type='text-single' label='Given Name' var='first'>
<required/>
</field>
<field type='text-single' label='Family Name' var='last'>
<required/>
</field>
<field type='text-single' label='Email Address' var='email'>
<required/>
</field>
<field type='list-single' label='Gender' var='x-gender'>
<option label='Male'><value>M</value></option>
<option label='Female'><value>F</value></option>
</field>
<field type='text-single' label='Invitation Token' var='auth-token'>
<required/>
</field>
</x>
</query>
</iq>
]]></example>
<p>The user then SHOULD return the form:</p>
<example caption='User Submits Registration Form'><![CDATA[
<iq type='set'
from='juliet@capulet.com/balcony'
to='contests.shakespeare.lit'
id='reg2'>
<query xmlns='jabber:iq:register'>
<x xmlns='jabber:x:data' type='submit'>
<field type='hidden' var='FORM_TYPE'>
<value>jabber:iq:register</value>
</field>
<field type='text-single' label='Given Name' var='first'>
<value>Juliet</value>
</field>
<field type='text-single' label='Family Name' var='last'>
<value>Capulet</value>
</field>
<field type='text-single' label='Email Address' var='email'>
<value>juliet@capulet.com</value>
</field>
<field type='list-single' label='Gender' var='x-gender'>
<value>F</value>
</field>
<field var='auth-token'>
<value>
37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643
</value>
</field>
</x>
</query>
</iq>
]]></example>
<p>If the token is acceptable, the service will then allow the consumer to register.</p>
</section2>
]]></example>
</section1>
<section1 topic='Determining Support' anchor='support'>
<p>If a service provides and accepts authorization tokens, it MUST advertise support for the 'urn:xmpp:tmp:auth-token' namespace in its disco#info replies (if provided) its &xep0115; notations &NSNOTE;.</p>
<p>If a service provides and accepts authorization tokens, it MUST advertise support for the 'urn:xmpp:tmp:oauth' namespace in its disco#info replies (if provided) its &xep0115; notations &NSNOTE;.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>To follow.</p>
<section2 topic='Signature Generation Algorithm' anchor='security-sig'>
<p>When sending OAuth Access Tokens over XMPP, the signature method MUST be HMAC-SHA1. The Signature Base String SHALL be constructed from the following items:</p>
<ul>
<li>The HTTP request method SHALL be the qname of the XMPP stanza element used, that is, either "message" or "presence" or "iq".</li>
<li>The request URL SHALL be the 'to' address of the XMPP stanza concatenated with the ampersand character "&amp;" and the 'from' address of the XMPP stanza.</li>
<li>The normalized request parameters string SHALL be all of the all oauth_* parameters included in the &lt;oauth/&gt; element.</li>
</ul>
<p>As an example, consider the following stanza:</p>
<code><![CDATA[
<iq to="x@example.com" from="y@example.org" id="1234">
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscribe node='mynode'/>
<oauth xmlns='urn:xmpp:tmp:oauth'>
<oauth_consumer_key>foo</oauth_consumer_key>
<oauth_token>bar</oauth_token>
<oauth_signature_method>HMAC-SHA1</oauth_signature_method>
<oauth_signature>h2vvES3WQpdYmjzUK7Fl2G1Nez8=</oauth_signature>
</oauth>
</pubsub>
</iq>
]]></code>
<p>The Signature Base String would be as follows (where line endings have been added for readability and denoted by the "\" character):</p>
<code><![CDATA[
iq&x%40example.com%26y%40example.org&oauth_consumer_key%3Dfoo\
%40oauth_signature_method%3DHMAC-SHA1%40oauth_token%3Dbar
]]></code>
<p>So assuming a consumer secret of 'consumersecret' and a token secret of 'tokensecret', the signature will be:</p>
<code><![CDATA[
h2vvES3WQpdYmjzUK7Fl2G1Nez8=
]]></code>
</section2>
<section2 topic='Replay Attacks' anchor='security-replay'>
<p>Signatures generated according to the signature generation algorithm might be subject to replay attacks. However, inclusions of the XMPP "to" and "from" addresses limits these attackes to compromised servers or client-to-server connections. OAuth tokens SHOULD be sent only over TLS-encrypted client-to-server connections, and all server-to-server connections SHOULD be TLS-enabled. Additional security can be provided using appropriate methods for the end-to-end encryption of XMPP traffic, such as &xep0027;, &rfc3923; &xep0116;, or &xep0246;.</p>
</section2>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<section2 topic='Protocol Namespaces' anchor='ns'>
<p>Until this specification advances to a status of Draft, its associated namespace shall be "urn:xmpp:tmp:auth-token"; upon advancement of this specification, the &REGISTRAR; shall issue a permanent namespace in accordance with the process defined in Section 4 of &xep0053;.</p>
</section2>
<section2 topic='Field Standardization' anchor='registrar-formtypes'>
<p>This specification adds one field to the existing FORM_TYPE for In-Band Registration.</p>
<section3 topic='jabber:iq:register' anchor='registrar-formtypes-register'>
<code><![CDATA[
<form_type>
<name>jabber:iq:register</name>
<field
var='auth-token'
type='text-single'
label='Authorization token'/>
</form_type>
]]></code>
</section3>
<p>Until this specification advances to a status of Draft, its associated namespace shall be "urn:xmpp:tmp:oauth"; upon advancement of this specification, the &REGISTRAR; shall issue a permanent namespace in accordance with the process defined in Section 4 of &xep0053;. The permanent namespace "urn:xmpp:oauth" will be requested, which is thought to be unique per the XMPP Registrar's requirements.</p>
</section2>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:tmp:auth-token'
xmlns='urn:xmpp:tmp:auth-token'
targetNamespace='urn:xmpp:tmp:oauth'
xmlns='urn:xmpp:tmp:oauth'
elementFormDefault='qualified'>
<xs:import
namespace='jabber:x:data'
schemaLocation='http://www.xmpp.org/schemas/x-data.xsd'/>
<xs:element name='token'>
<xs:element name='oauth'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base='xs:string'>
<xs:attribute name='consumer' type='xs:string' use='optional'/>
<xs:attribute name='expires' type='xs:string' use='optional'/>
<xs:attribute name='node' type='xs:string' use='optional'/>
<xs:attribute name='service' type='xs:string' use='optional'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name='token-required'>
<xs:complexType>
<xs:choice xmlns:xdata='jabber:x:data' minOccurs='0' maxOccurs='1'>
<xs:element ref='xdata:x'/>
<xs:choice>
<xs:element name='oauth_consumer_key' type='xs:string'/>
<xs:element name='oauth_nonce' type='xs:string'/>
<xs:element name='oauth_signature' type='xs:string'/>
<xs:element name='oauth_signature_method' type='xs:string'/>
<xs:element name='oauth_timestamp' type='xs:string'/>
<xs:element name='oauth_token' type='xs:string'/>
<xs:element name='oauth_token_secret' type='xs:string'/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:simpleType name='empty'>
<xs:restriction base='xs:string'>
<xs:enumeration value=''/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
]]></code>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>Thanks to Dave Cridland and Pedro Melo for their suggestions. Aspects of this specification were inspired by &rfc4467;. Some of the terminology in this specification was borrowed from OAuth.</p>
<p>The author gratefully acknowledges the contributions of Blaine Cook, Leah Culver, Kellan Elliott-McCrea, Seth Fitzsimmons, Nathan Fritz, Evan Henshaw-Plath, Joe Hildebrand, and Ralph Meijer to the content of this specification, as provided during the XMPP Summit held in Portland, Oregon, on July 21 and 22, 2008. Thanks also to Dave Cridland and Pedro Melo for their comments on an early draft.</p>
</section1>
</xep>