3
3
from http import HTTPStatus
4
4
import reprlib
5
5
import json
6
+ from typing import Optional , Tuple
6
7
7
8
from aiocometd import AuthExtension
9
+ from aiocometd .typing import JsonObject , JsonLoader , JsonDumper , Payload , \
10
+ Headers
8
11
from aiohttp import ClientSession
9
12
from aiohttp .client_exceptions import ClientError
10
13
20
23
class AuthenticatorBase (AuthExtension ):
21
24
"""Abstract base class to serve as a base for implementing concrete
22
25
authenticators"""
23
- def __init__ (self , sandbox = False , json_dumps = json .dumps ,
24
- json_loads = json .loads ):
26
+ def __init__ (self , sandbox : bool = False ,
27
+ json_dumps : JsonDumper = json .dumps ,
28
+ json_loads : JsonLoader = json .loads ) -> None :
25
29
"""
26
- :param bool sandbox: Marks whether the authentication has to be done \
30
+ :param sandbox: Marks whether the authentication has to be done \
27
31
for a sandbox org or for a production org
28
32
:param json_dumps: Function for JSON serialization, the default is \
29
33
:func:`json.dumps`
30
- :type json_dumps: :func:`callable`
31
34
:param json_loads: Function for JSON deserialization, the default is \
32
35
:func:`json.loads`
33
- :type json_loads: :func:`callable`
34
36
"""
35
37
#: Marks whether the authentication has to be done for a sandbox org \
36
38
#: or for a production org
37
39
self ._sandbox = sandbox
38
40
#: Salesforce session ID that can be used with the web services API
39
- self .access_token = None
41
+ self .access_token : Optional [ str ] = None
40
42
#: Value is Bearer for all responses that include an access token
41
- self .token_type = None
43
+ self .token_type : Optional [ str ] = None
42
44
#: A URL indicating the instance of the user’s org
43
- self .instance_url = None
45
+ self .instance_url : Optional [ str ] = None
44
46
#: Identity URL that can be used to both identify the user and query \
45
47
#: for more information about the user
46
- self .id = None # pylint: disable=invalid-name
48
+ self .id : Optional [ str ] = None # pylint: disable=invalid-name
47
49
#: Base64-encoded HMAC-SHA256 signature signed with the consumer’s \
48
50
#: private key containing the concatenated ID and issued_at. Use to \
49
51
#: verify that the identity URL hasn’t changed since the server sent it
50
- self .signature = None
52
+ self .signature : Optional [ str ] = None
51
53
#: Timestamp when the signature was created
52
- self .issued_at = None
54
+ self .issued_at : Optional [ str ] = None
53
55
#: Function for JSON serialization
54
56
self .json_dumps = json_dumps
55
57
#: Function for JSON deserialization
56
58
self .json_loads = json_loads
57
59
58
60
@property
59
- def _token_url (self ):
61
+ def _token_url (self ) -> str :
60
62
"""The URL that should be used for token requests"""
61
63
if self ._sandbox :
62
64
return SANDBOX_TOKEN_URL
63
65
return TOKEN_URL
64
66
65
- async def outgoing (self , payload , headers ):
67
+ async def outgoing (self , payload : Payload , headers : Headers ) -> None :
68
+ """Process outgoing *payload* and *headers*
69
+
70
+ Called just before a payload is sent to insert the ``Authorization`` \
71
+ header value.
72
+
73
+ :param payload: List of outgoing messages
74
+ :param headers: Headers to send
75
+ :raise AuthenticationError: If the value of :py:attr:`~token_type` or \
76
+ :py:attr:`~access_token` is ``None``. In other words, it's raised if \
77
+ the method is called without authenticating first.
78
+ """
79
+ if self .token_type is None or self .access_token is None :
80
+ raise AuthenticationError ("Unknown token_type and access_token "
81
+ "values. Method called without "
82
+ "authenticating first." )
66
83
headers ["Authorization" ] = self .token_type + " " + self .access_token
67
84
68
- async def incoming (self , payload , headers = None ):
85
+ async def incoming (self , payload : Payload ,
86
+ headers : Optional [Headers ] = None ) -> None :
69
87
pass
70
88
71
- async def authenticate (self ):
89
+ async def authenticate (self ) -> None :
72
90
"""Called on initialization and after a failed authentication attempt
73
91
74
92
:raise AuthenticationError: If the server rejects the authentication \
@@ -91,11 +109,10 @@ async def authenticate(self):
91
109
self .__dict__ .update (response_data )
92
110
93
111
@abstractmethod
94
- async def _authenticate (self ):
112
+ async def _authenticate (self ) -> Tuple [ int , JsonObject ] :
95
113
"""Authenticate the user
96
114
97
115
:return: The status code and response data from the server's response
98
- :rtype: tuple(int, dict)
99
116
:raise aiohttp.client_exceptions.ClientError: If a network failure \
100
117
occurs
101
118
"""
@@ -106,23 +123,23 @@ async def _authenticate(self):
106
123
107
124
class PasswordAuthenticator (AuthenticatorBase ):
108
125
"""Authenticator for using the OAuth 2.0 Username-Password Flow"""
109
- def __init__ (self , consumer_key , consumer_secret , username , password ,
110
- sandbox = False , json_dumps = json .dumps , json_loads = json .loads ):
126
+ def __init__ (self , consumer_key : str , consumer_secret : str ,
127
+ username : str , password : str , sandbox : bool = False ,
128
+ json_dumps : JsonDumper = json .dumps ,
129
+ json_loads : JsonLoader = json .loads ) -> None :
111
130
"""
112
- :param str consumer_key: Consumer key from the Salesforce connected \
131
+ :param consumer_key: Consumer key from the Salesforce connected \
113
132
app definition
114
- :param str consumer_secret: Consumer secret from the Salesforce \
133
+ :param consumer_secret: Consumer secret from the Salesforce \
115
134
connected app definition
116
- :param str username: Salesforce username
117
- :param str password: Salesforce password
118
- :param bool sandbox: Marks whether the authentication has to be done \
135
+ :param username: Salesforce username
136
+ :param password: Salesforce password
137
+ :param sandbox: Marks whether the authentication has to be done \
119
138
for a sandbox org or for a production org
120
139
:param json_dumps: Function for JSON serialization, the default is \
121
140
:func:`json.dumps`
122
- :type json_dumps: :func:`callable`
123
141
:param json_loads: Function for JSON deserialization, the default is \
124
142
:func:`json.loads`
125
- :type json_loads: :func:`callable`
126
143
"""
127
144
super ().__init__ (sandbox = sandbox ,
128
145
json_dumps = json_dumps ,
@@ -136,15 +153,15 @@ def __init__(self, consumer_key, consumer_secret, username, password,
136
153
#: Salesforce password
137
154
self .password = password
138
155
139
- def __repr__ (self ):
156
+ def __repr__ (self ) -> str :
140
157
"""Formal string representation"""
141
158
cls_name = type (self ).__name__
142
159
return f"{ cls_name } (consumer_key={ reprlib .repr (self .client_id )} ," \
143
160
f"consumer_secret={ reprlib .repr (self .client_secret )} , " \
144
161
f"username={ reprlib .repr (self .username )} , " \
145
162
f"password={ reprlib .repr (self .password )} )"
146
163
147
- async def _authenticate (self ):
164
+ async def _authenticate (self ) -> Tuple [ int , JsonObject ] :
148
165
async with ClientSession (json_serialize = self .json_dumps ) as session :
149
166
data = {
150
167
"grant_type" : "password" ,
@@ -160,24 +177,24 @@ async def _authenticate(self):
160
177
161
178
class RefreshTokenAuthenticator (AuthenticatorBase ):
162
179
"""Authenticator for using the OAuth 2.0 Refresh Token Flow"""
163
- def __init__ (self , consumer_key , consumer_secret , refresh_token ,
164
- sandbox = False , json_dumps = json .dumps , json_loads = json .loads ):
180
+ def __init__ (self , consumer_key : str , consumer_secret : str ,
181
+ refresh_token : str , sandbox : bool = False ,
182
+ json_dumps : JsonDumper = json .dumps ,
183
+ json_loads : JsonLoader = json .loads ) -> None :
165
184
"""
166
- :param str consumer_key: Consumer key from the Salesforce connected \
185
+ :param consumer_key: Consumer key from the Salesforce connected \
167
186
app definition
168
- :param str consumer_secret: Consumer secret from the Salesforce \
187
+ :param consumer_secret: Consumer secret from the Salesforce \
169
188
connected app definition
170
- :param str refresh_token: A refresh token obtained from Salesforce \
189
+ :param refresh_token: A refresh token obtained from Salesforce \
171
190
by using one of its authentication methods (for example with the \
172
191
OAuth 2.0 Web Server Authentication Flow)
173
- :param bool sandbox: Marks whether the authentication has to be done \
192
+ :param sandbox: Marks whether the authentication has to be done \
174
193
for a sandbox org or for a production org
175
194
:param json_dumps: Function for JSON serialization, the default is \
176
195
:func:`json.dumps`
177
- :type json_dumps: :func:`callable`
178
196
:param json_loads: Function for JSON deserialization, the default is \
179
197
:func:`json.loads`
180
- :type json_loads: :func:`callable`
181
198
"""
182
199
super ().__init__ (sandbox = sandbox ,
183
200
json_dumps = json_dumps ,
@@ -189,14 +206,14 @@ def __init__(self, consumer_key, consumer_secret, refresh_token,
189
206
#: Salesforce refresh token
190
207
self .refresh_token = refresh_token
191
208
192
- def __repr__ (self ):
209
+ def __repr__ (self ) -> str :
193
210
"""Formal string representation"""
194
211
cls_name = type (self ).__name__
195
212
return f"{ cls_name } (consumer_key={ reprlib .repr (self .client_id )} ," \
196
213
f"consumer_secret={ reprlib .repr (self .client_secret )} , " \
197
214
f"refresh_token={ reprlib .repr (self .refresh_token )} )"
198
215
199
- async def _authenticate (self ):
216
+ async def _authenticate (self ) -> Tuple [ int , JsonObject ] :
200
217
async with ClientSession (json_serialize = self .json_dumps ) as session :
201
218
data = {
202
219
"grant_type" : "refresh_token" ,
0 commit comments