Skip to content

Commit 291f3fd

Browse files
authored
Release/2.56.1 (#641)
Adds MFA compatibility and credential local caching to avoid having to fill MFA code very often.
1 parent 789e3a8 commit 291f3fd

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

pycarol/auth/PwdAuth.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
import types
77
import time
8+
import json
9+
from pathlib import Path
10+
from .. import __TEMP_STORAGE__
811
from .PwdAuth_cloner import PwdAuthCloner
912

1013

@@ -20,12 +23,13 @@ class PwdAuth:
2023
2124
"""
2225

23-
def __init__(self, user, password):
26+
def __init__(self, user, password, mfa_code=None):
2427
self.user = user
2528
self.password = password
2629
self._token = None
2730
self.carol = None
2831
self.connector_id = None
32+
self.mfa_code = mfa_code
2933

3034
def _set_token(self, data):
3135
self._token = types.SimpleNamespace()
@@ -34,6 +38,8 @@ def _set_token(self, data):
3438
self._token.expiration = data['timeIssuedInMillis'] + (
3539
data['expires_in'] * 1000)
3640

41+
self._save_token(data)
42+
3743
def set_connector_id(self, connector_id):
3844
self.connector_id = connector_id
3945

@@ -54,6 +60,27 @@ def login(self, carol):
5460
"""
5561
self.carol = carol
5662

63+
self._temp_file_name = f".pycarol_token_{self.user}_{self.carol.organization}_{self.carol.domain}.json"
64+
self._tmp_filepath = Path(__TEMP_STORAGE__) / self._temp_file_name
65+
66+
if self._tmp_filepath.exists():
67+
with open(self._tmp_filepath, "r", encoding="utf-8") as file:
68+
token_data = json.load(file)
69+
self._set_token(token_data)
70+
71+
# Try access token
72+
resp = self.carol.call_api(f'v5/oauth2/token/{token_data["access_token"]}', auth=False, errors="ignore")
73+
if resp.get('access_token') and resp.get('errorCode') is None:
74+
return
75+
76+
# Try refresh token
77+
try:
78+
self._refresh_token()
79+
return
80+
except Exception:
81+
pass
82+
83+
# New login
5784
data = {
5885
'username': self.user,
5986
'password': self.password,
@@ -62,13 +89,30 @@ def login(self, carol):
6289
'connectorId': carol.connector_id,
6390
'orgSubdomain': carol.organization
6491
}
65-
resp = self.carol.call_api('v2/oauth2/token', auth=False, data=data,
92+
93+
resp = self.carol.call_api('v5/oauth2/token', auth=False, data=data,
6694
content_type='application/x-www-form-urlencoded')
6795

96+
if resp.get('mfa_token'):
97+
mfa_code = input('Input your TOTVS Carol - MFA code: ') if self.mfa_code is None else self.mfa_code
98+
99+
data = {
100+
'mfaCode': mfa_code
101+
}
102+
103+
resp = self.carol.call_api('v5/oauth2/token/mfa/authenticate', auth=False, data=data,
104+
extra_headers={'Authorization': resp['mfa_token']},
105+
content_type='application/x-www-form-urlencoded')
106+
68107
self._set_token(resp)
69108
if self.carol.verbose:
70109
print("Token: {}".format(self._token.access_token))
71110

111+
def _save_token(self, data):
112+
self._tmp_filepath.parent.mkdir(parents=True, exist_ok=True)
113+
with open(self._tmp_filepath, "w", encoding="utf-8") as file:
114+
json.dump(data, file)
115+
72116
def authenticate_request(self, headers):
73117
headers['Authorization'] = self.get_access_token()
74118

@@ -92,7 +136,7 @@ def get_access_token(self):
92136
return self._token.access_token
93137

94138
def _refresh_token(self):
95-
resp = self.carol.call_api('v2/oauth2/token', auth=False, data={
139+
resp = self.carol.call_api('v5/oauth2/token', auth=False, data={
96140
'grant_type': 'refresh_token',
97141
'refresh_token': self._token.refresh_token
98142
}, content_type='application/x-www-form-urlencoded')

0 commit comments

Comments
 (0)