Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/clients/service_application.py: 26%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

34 statements  

1# -*- coding: utf-8 -*- 

2""" 

3oauthlib.oauth2.rfc6749 

4~~~~~~~~~~~~~~~~~~~~~~~ 

5 

6This module is an implementation of various logic needed 

7for consuming and providing OAuth 2.0 RFC6749. 

8""" 

9import time 

10 

11from oauthlib.common import to_unicode 

12 

13from ..parameters import prepare_token_request 

14from .base import Client 

15 

16 

17class ServiceApplicationClient(Client): 

18 """A public client utilizing the JWT bearer grant. 

19 

20 JWT bearer tokes can be used to request an access token when a client 

21 wishes to utilize an existing trust relationship, expressed through the 

22 semantics of (and digital signature or keyed message digest calculated 

23 over) the JWT, without a direct user approval step at the authorization 

24 server. 

25 

26 This grant type does not involve an authorization step. It may be 

27 used by both public and confidential clients. 

28 """ 

29 

30 grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer' 

31 

32 def __init__(self, client_id, private_key=None, subject=None, issuer=None, 

33 audience=None, **kwargs): 

34 """Initialize a JWT client with defaults for implicit use later. 

35 

36 :param client_id: Client identifier given by the OAuth provider upon 

37 registration. 

38 

39 :param private_key: Private key used for signing and encrypting. 

40 Must be given as a string. 

41 

42 :param subject: The principal that is the subject of the JWT, i.e. 

43 which user is the token requested on behalf of. 

44 For example, ``foo@example.com. 

45 

46 :param issuer: The JWT MUST contain an "iss" (issuer) claim that 

47 contains a unique identifier for the entity that issued 

48 the JWT. For example, ``your-client@provider.com``. 

49 

50 :param audience: A value identifying the authorization server as an 

51 intended audience, e.g. 

52 ``https://provider.com/oauth2/token``. 

53 

54 :param kwargs: Additional arguments to pass to base client, such as 

55 state and token. See ``Client.__init__.__doc__`` for 

56 details. 

57 """ 

58 super().__init__(client_id, **kwargs) 

59 self.private_key = private_key 

60 self.subject = subject 

61 self.issuer = issuer 

62 self.audience = audience 

63 

64 def prepare_request_body(self, 

65 private_key=None, 

66 subject=None, 

67 issuer=None, 

68 audience=None, 

69 expires_at=None, 

70 issued_at=None, 

71 extra_claims=None, 

72 body='', 

73 scope=None, 

74 include_client_id=False, 

75 **kwargs): 

76 """Create and add a JWT assertion to the request body. 

77 

78 :param private_key: Private key used for signing and encrypting. 

79 Must be given as a string. 

80 

81 :param subject: (sub) The principal that is the subject of the JWT, 

82 i.e. which user is the token requested on behalf of. 

83 For example, ``foo@example.com. 

84 

85 :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that 

86 contains a unique identifier for the entity that issued 

87 the JWT. For example, ``your-client@provider.com``. 

88 

89 :param audience: (aud) A value identifying the authorization server as an 

90 intended audience, e.g. 

91 ``https://provider.com/oauth2/token``. 

92 

93 :param expires_at: A unix expiration timestamp for the JWT. Defaults 

94 to an hour from now, i.e. ``round(time.time()) + 3600``. 

95 

96 :param issued_at: A unix timestamp of when the JWT was created. 

97 Defaults to now, i.e. ``time.time()``. 

98 

99 :param extra_claims: A dict of additional claims to include in the JWT. 

100 

101 :param body: Existing request body (URL encoded string) to embed parameters 

102 into. This may contain extra parameters. Default ''. 

103 

104 :param scope: The scope of the access request. 

105 

106 :param include_client_id: `True` to send the `client_id` in the 

107 body of the upstream request. This is required 

108 if the client is not authenticating with the 

109 authorization server as described in 

110 `Section 3.2.1`_. False otherwise (default). 

111 :type include_client_id: Boolean 

112 

113 :param not_before: A unix timestamp after which the JWT may be used. 

114 Not included unless provided. * 

115 

116 :param jwt_id: A unique JWT token identifier. Not included unless 

117 provided. * 

118 

119 :param kwargs: Extra credentials to include in the token request. 

120 

121 Parameters marked with a `*` above are not explicit arguments in the 

122 function signature, but are specially documented arguments for items 

123 appearing in the generic `**kwargs` keyworded input. 

124 

125 The "scope" parameter may be used, as defined in the Assertion 

126 Framework for OAuth 2.0 Client Authentication and Authorization Grants 

127 [I-D.ietf-oauth-assertions] specification, to indicate the requested 

128 scope. 

129 

130 Authentication of the client is optional, as described in 

131 `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the 

132 "client_id" is only needed when a form of client authentication that 

133 relies on the parameter is used. 

134 

135 The following non-normative example demonstrates an Access Token 

136 Request with a JWT as an authorization grant (with extra line breaks 

137 for display purposes only): 

138 

139 .. code-block: http 

140 

141 POST /token.oauth2 HTTP/1.1 

142 Host: as.example.com 

143 Content-Type: application/x-www-form-urlencoded 

144 

145 grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer 

146 &assertion=eyJhbGciOiJFUzI1NiJ9. 

147 eyJpc3Mi[...omitted for brevity...]. 

148 J9l-ZhwP[...omitted for brevity...] 

149 

150 .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 

151 """ 

152 import jwt # noqa: PLC0415 

153 

154 key = private_key or self.private_key 

155 if not key: 

156 raise ValueError('An encryption key must be supplied to make JWT' 

157 ' token requests.') 

158 claim = { 

159 'iss': issuer or self.issuer, 

160 'aud': audience or self.audience, 

161 'sub': subject or self.subject, 

162 'exp': int(expires_at or time.time() + 3600), 

163 'iat': int(issued_at or time.time()), 

164 } 

165 

166 for attr in ('iss', 'aud', 'sub'): 

167 if claim[attr] is None: 

168 raise ValueError( 

169 'Claim must include %s but none was given.' % attr) 

170 

171 if 'not_before' in kwargs: 

172 claim['nbf'] = kwargs.pop('not_before') 

173 

174 if 'jwt_id' in kwargs: 

175 claim['jti'] = kwargs.pop('jwt_id') 

176 

177 claim.update(extra_claims or {}) 

178 

179 assertion = jwt.encode(claim, key, 'RS256') 

180 assertion = to_unicode(assertion) 

181 

182 kwargs['client_id'] = self.client_id 

183 kwargs['include_client_id'] = include_client_id 

184 scope = self.scope if scope is None else scope 

185 return prepare_token_request(self.grant_type, 

186 body=body, 

187 assertion=assertion, 

188 scope=scope, 

189 **kwargs)