1
- import logging
1
+ '''
2
+
3
+ Created on Dec 23, 2020
4
+ @author: ar-calder
5
+
6
+ '''
7
+
2
8
import requests
9
+ import logging
3
10
import json
4
- from operator import itemgetter
5
- import urllib .parse
11
+ from datetime import datetime , timedelta
12
+
13
+ logger = logging .getLogger (__name__ )
14
+
15
+ class BearerAuth (requests .auth .AuthBase ):
16
+
17
+ from .Exceptions import http_exception_handler
18
+
19
+ def __init__ (
20
+ self ,
21
+ session = None ,
22
+ token = None ,
23
+ base_url = None ,
24
+ verify = True ,
25
+ timeout = 15 ,
26
+ ):
27
+
28
+ if any (arg == False for arg in (token , base_url )):
29
+ raise ValueError (
30
+ 'token & base_url are required'
31
+ )
32
+
33
+ self .verify = verify
34
+ self .client_token = token
35
+ self .auth_token = None
36
+ self .csrf_token = None
37
+ self .valid_until = datetime .utcnow ()
38
+
39
+ self .auth_url = requests .compat .urljoin (base_url , '/api/tokens/authenticate' )
40
+ self .session = session or requests .session ()
41
+ self .timeout = timeout
42
+
43
+
44
+ def __call__ (self , request ):
45
+ if not self .auth_token or self .valid_until < datetime .utcnow ():
46
+ # If authentication token not set or no longer valid
47
+ self .authenticate ()
48
+
49
+ request .headers .update ({
50
+ "authorization" : f"bearer { self .auth_token } " ,
51
+ "X-CSRF-TOKEN" : self .csrf_token
52
+ })
53
+
54
+ return request
55
+
56
+
57
+ def authenticate (self ):
58
+ if not self .verify :
59
+ requests .packages .urllib3 .disable_warnings ()
60
+ # Announce this on every auth attempt, as a little incentive to properly configure certs
61
+ logger .warn ("ssl verification disabled, connection insecure. do NOT use verify=False in production!" )
62
+
63
+ try :
64
+ response = self .session .request (
65
+ method = 'POST' ,
66
+ url = self .auth_url ,
67
+ headers = {
68
+ "Authorization" : f"token { self .client_token } "
69
+ },
70
+ verify = self .verify ,
71
+ timeout = self .timeout
72
+ )
73
+
74
+ if response .status_code / 100 != 2 :
75
+ self .http_exception_handler (
76
+ response = response ,
77
+ name = "authenticate"
78
+ )
79
+
80
+ content = response .json ()
81
+ self .csrf_token = response .headers .get ('X-CSRF-TOKEN' )
82
+ self .auth_token = content .get ('bearerToken' )
83
+ self .valid_until = datetime .utcnow () + timedelta (milliseconds = int (content .get ('expiresInMilliseconds' , 0 )))
6
84
7
- logger = logging .getLogger (__name__ )
85
+ # Do not handle exceptions - just just more details as to possible causes
86
+ # Thus we do not catch a JsonDecodeError here even though it may occur
87
+ # - no futher details to give.
88
+ except requests .exceptions .ConnectTimeout as connect_timeout :
89
+ logger .critical (f"could not establish a connection within { self .timeout } s, this may be indicative of proxy misconfiguration" )
90
+ raise connect_timeout
91
+ except requests .exceptions .ReadTimeout as read_timeout :
92
+ logger .critical (f"slow or unstable connection, consider increasing timeout (currently set to { self .timeout } s)" )
93
+ raise read_timeout
94
+ else :
95
+ logger .info (f"success: auth granted until { self .valid_until } UTC" )
0 commit comments