Merge pull request #3 from guyrt/master
[twitter-api-cdsw-solutions] / oauthlib / oauth2 / rfc6749 / clients / service_application.py
1 # -*- coding: utf-8 -*-
2 """
3 oauthlib.oauth2.rfc6749
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
6 This module is an implementation of various logic needed
7 for consuming and providing OAuth 2.0 RFC6749.
8 """
9 from __future__ import absolute_import, unicode_literals
10
11 import time
12
13 from oauthlib.common import to_unicode
14
15 from .base import Client
16 from ..parameters import prepare_token_request
17 from ..parameters import parse_token_response
18
19
20 class ServiceApplicationClient(Client):
21     """A public client utilizing the JWT bearer grant.
22
23     JWT bearer tokes can be used to request an access token when a client
24     wishes to utilize an existing trust relationship, expressed through the
25     semantics of (and digital signature or keyed message digest calculated
26     over) the JWT, without a direct user approval step at the authorization
27     server.
28
29     This grant type does not involve an authorization step. It may be
30     used by both public and confidential clients.
31     """
32
33     grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
34
35     def __init__(self, client_id, private_key=None, subject=None, issuer=None,
36                  audience=None, **kwargs):
37         """Initalize a JWT client with defaults for implicit use later.
38
39         :param client_id: Client identifier given by the OAuth provider upon
40                           registration.
41
42         :param private_key: Private key used for signing and encrypting.
43                             Must be given as a string.
44
45         :param subject: The principal that is the subject of the JWT, i.e. 
46                         which user is the token requested on behalf of.
47                         For example, ``foo@example.com.
48
49         :param issuer: The JWT MUST contain an "iss" (issuer) claim that
50                        contains a unique identifier for the entity that issued
51                        the JWT. For example, ``your-client@provider.com``. 
52
53         :param audience: A value identifying the authorization server as an
54                          intended audience, e.g.
55                          ``https://provider.com/oauth2/token``.
56
57         :param kwargs: Additional arguments to pass to base client, such as
58                        state and token. See Client.__init__.__doc__ for 
59                        details.
60         """
61         super(ServiceApplicationClient, self).__init__(client_id, **kwargs)
62         self.private_key = private_key
63         self.subject = subject
64         self.issuer = issuer
65         self.audience = audience
66
67     def prepare_request_body(self, 
68                              private_key=None,
69                              subject=None, 
70                              issuer=None, 
71                              audience=None, 
72                              expires_at=None, 
73                              issued_at=None,
74                              extra_claims=None,
75                              body='', 
76                              scope=None, 
77                              **kwargs):
78         """Create and add a JWT assertion to the request body.
79
80         :param private_key: Private key used for signing and encrypting.
81                             Must be given as a string.
82
83         :param subject: (sub) The principal that is the subject of the JWT,
84                         i.e.  which user is the token requested on behalf of.
85                         For example, ``foo@example.com.
86
87         :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that
88                        contains a unique identifier for the entity that issued
89                        the JWT. For example, ``your-client@provider.com``. 
90
91         :param audience: (aud) A value identifying the authorization server as an
92                          intended audience, e.g.
93                          ``https://provider.com/oauth2/token``.
94
95         :param expires_at: A unix expiration timestamp for the JWT. Defaults
96                            to an hour from now, i.e. ``time.time() + 3600``.
97
98         :param issued_at: A unix timestamp of when the JWT was created.
99                           Defaults to now, i.e. ``time.time()``.
100
101         :param not_before: A unix timestamp after which the JWT may be used.
102                            Not included unless provided.
103
104         :param jwt_id: A unique JWT token identifier. Not included unless
105                        provided.
106
107         :param extra_claims: A dict of additional claims to include in the JWT.
108
109         :param scope: The scope of the access request.
110
111         :param body: Request body (string) with extra parameters.
112
113         :param kwargs: Extra credentials to include in the token request.
114
115         The "scope" parameter may be used, as defined in the Assertion
116         Framework for OAuth 2.0 Client Authentication and Authorization Grants
117         [I-D.ietf-oauth-assertions] specification, to indicate the requested
118         scope.
119
120         Authentication of the client is optional, as described in 
121         `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the
122         "client_id" is only needed when a form of client authentication that
123         relies on the parameter is used.
124
125         The following non-normative example demonstrates an Access Token
126         Request with a JWT as an authorization grant (with extra line breaks
127         for display purposes only):
128
129         .. code-block: http
130
131             POST /token.oauth2 HTTP/1.1
132             Host: as.example.com
133             Content-Type: application/x-www-form-urlencoded
134
135             grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
136             &assertion=eyJhbGciOiJFUzI1NiJ9.
137             eyJpc3Mi[...omitted for brevity...].
138             J9l-ZhwP[...omitted for brevity...]
139
140         .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
141         """
142         import jwt
143
144         key = private_key or self.private_key
145         if not key:
146             raise ValueError('An encryption key must be supplied to make JWT'
147                              ' token requests.')
148         claim = {
149             'iss': issuer or self.issuer,
150             'aud': audience or self.issuer,
151             'sub': subject or self.issuer,
152             'exp': int(expires_at or time.time() + 3600),
153             'iat': int(issued_at or time.time()),
154         }
155
156         for attr in ('iss', 'aud', 'sub'):
157             if claim[attr] is None:
158                 raise ValueError(
159                         'Claim must include %s but none was given.' % attr)
160
161         if 'not_before' in kwargs:
162             claim['nbf'] = kwargs.pop('not_before')
163
164         if 'jwt_id' in kwargs:
165             claim['jti'] = kwargs.pop('jwt_id')
166
167         claim.update(extra_claims or {})
168
169         assertion = jwt.encode(claim, key, 'RS256')
170         assertion = to_unicode(assertion)
171
172         return prepare_token_request(self.grant_type,
173                                      body=body,
174                                      assertion=assertion,
175                                      scope=scope, 
176                                      **kwargs)

Benjamin Mako Hill || Want to submit a patch?