Skip to content

Commit 91f01ae

Browse files
committed
Added BearerAuth class to leverage requests.auth
1 parent 89c3106 commit 91f01ae

File tree

1 file changed

+92
-4
lines changed

1 file changed

+92
-4
lines changed

blackduck/Authentication.py

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,95 @@
1-
import logging
1+
'''
2+
3+
Created on Dec 23, 2020
4+
@author: ar-calder
5+
6+
'''
7+
28
import requests
9+
import logging
310
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)))
684

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

Comments
 (0)