Skip to content

Commit 4a334de

Browse files
authored
Saimon/Bearer Authentication (#334)
1 parent 43a78c7 commit 4a334de

16 files changed

Lines changed: 271 additions & 169 deletions

File tree

cterasdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# pylint: disable=wrong-import-position
2-
import cterasdk.settings # noqa: E402, F401
32
import cterasdk.exceptions # noqa: E402, F401
43

4+
from .settings import settings # noqa: E402, F401
55
from .common import Object, PolicyRule # noqa: E402, F401
66
from .convert import fromjsonstr, tojsonstr, fromxmlstr, toxmlstr # noqa: E402, F401
77
from .core import query # noqa: E402, F401

cterasdk/cio/core/commands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ def _before_command(self):
797797
logger.info('Creating Public Link: %s', self.path)
798798

799799
def get_parameter(self):
800-
access = {'RO': 'ReadOnly', 'RW': 'ReadWrite', 'PO': 'PreviewOnly'}.get(self.access)
800+
access = {k: v for k, v in FileAccessMode.__dict__.items() if not k.startswith('_') and k != 'NA'}.get(self.access, None)
801801
expire_on = DateTimeUtils.get_expiration_date(self.expire_in).strftime('%Y-%m-%d')
802802
param = CreateShareParam.instance(path=self.path.absolute_encode, access=access, expire_on=expire_on)
803803
return param

cterasdk/cio/core/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ class PortalVolume(Object):
314314
:ivar str name: Cloud Drive Folder Name
315315
:ivar int group: Folder Group ID
316316
:ivar bool protected: Passphrase-Protected
317-
:ivar cterasdk.core.types.VolumeOwner owner: Volume owner information.
317+
:ivar cterasdk.cio.core.types.VolumeOwner owner: Volume owner information.
318318
"""
319319
def __init__(self, i, name, group, protected, owner):
320320
super().__init__(id=i, name=name, group=group, protected=protected, owner=owner)

cterasdk/clients/async_requests.py

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@
55

66
from yarl import URL
77
from ..exceptions.transport import TLSError
8-
8+
from .settings import from_configuration
99

1010
logger = logging.getLogger('cterasdk.http')
1111

1212

1313
class Session:
1414
"""Asynchronous HTTP Session"""
1515

16-
def __init__(self, settings, trace):
17-
self._settings = settings
18-
self._trace = trace
16+
def __init__(self, configuration):
17+
self._configuration = configuration
18+
self._cookie_jar = CachedCookieJar()
1919
self._session = None
2020

2121
@property
2222
def session(self):
2323
if self.closed:
24-
self._session = aiohttp.ClientSession(**self._settings, **self._trace)
24+
self._session = aiohttp.ClientSession(**from_configuration(self._configuration), trust_env=True)
25+
self._cookie_jar.register(self._session)
26+
self._cookie_jar.update_cookie_jar()
2527
return self._session
2628

2729
@property
28-
def cookies(self):
29-
return CookieJar(self.session.cookie_jar)
30+
def cookie_jar(self):
31+
return self._cookie_jar
3032

3133
async def request(self, r, *, await_promise=False, on_response=None):
3234
if await_promise:
@@ -80,22 +82,62 @@ async def wrapper(self, n=-1):
8082
return wrapper
8183

8284

83-
class CookieJar:
85+
def ensure_session(func):
86+
def wrapper(self, *args, **kwargs):
87+
if self._session is not None and not self._session.closed: # pylint: disable=protected-access
88+
return func(self, *args, **kwargs)
89+
return None
90+
return wrapper
8491

85-
def __init__(self, cookie_jar):
86-
self._cookie_jar = cookie_jar
8792

88-
def update_cookies(self, cookies, response_url=None):
89-
self._cookie_jar.update_cookies(cookies, URL(response_url))
93+
def update_session(func):
94+
def wrapper(self, *args, **kwargs):
95+
func(self, *args, **kwargs)
96+
self.update_cookie_jar()
97+
return wrapper
9098

91-
def get(self, key):
92-
for cookie in self._cookie_jar:
93-
if cookie.key == key:
94-
return cookie.value
95-
return None
9699

100+
class CachedCookieJar:
101+
102+
def __init__(self):
103+
self._cache = {}
104+
self._session = None
105+
106+
def register(self, session):
107+
self._session = session
108+
109+
@ensure_session
110+
def update_cookie_jar(self):
111+
for response_url, cookies in self._cache.items():
112+
self._session.cookie_jar.update_cookies(cookies, URL(response_url))
113+
self._cache.clear()
114+
115+
@update_session
116+
def update_cookies(self, cookies, response_url=None):
117+
logger.debug('Cookie update. Scope: %s', response_url)
118+
self._cache[response_url] = cookies
119+
120+
@ensure_session
121+
def filter_cookies(self, response_url):
122+
return self._session.cookie_jar.filter_cookies(response_url)
123+
124+
@ensure_session
125+
def get(self, response_url, key):
126+
"""
127+
Get Cookie Value
128+
129+
:param str response_url: URL
130+
:param str key: Cookie Key
131+
:returns: Cookie Value
132+
:rtype: str
133+
"""
134+
cookies = self._session.cookie_jar.filter_cookies(response_url)
135+
cookie = cookies.get(key, None)
136+
return cookie.value if cookie else None
137+
138+
@ensure_session
97139
def clear(self):
98-
self._cookie_jar.clear()
140+
return self._session.cookie_jar.clear()
99141

100142

101143
class BaseRequest:

cterasdk/clients/base.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import threading
44
import aiohttp
55
from . import async_requests, errors
6-
from .settings import ClientSessionSettings, TraceSettings
6+
from .settings import get_configuration
77
from ..common import utils
88

99

@@ -17,22 +17,7 @@
1717
logger = logging.getLogger('cterasdk.http')
1818

1919

20-
class CookieJar:
21-
22-
def __init__(self, cookies):
23-
self._cookies = cookies
24-
25-
def get(self, key):
26-
return self._cookies.get(key)
27-
28-
def update(self, cookies, response_url):
29-
self._cookies.update_cookies(cookies, response_url)
30-
31-
def clear(self):
32-
self._cookies.clear()
33-
34-
35-
class PersistentHeaders:
20+
class Headers:
3621
"""Headers to include in every request"""
3722

3823
def __init__(self):
@@ -48,6 +33,9 @@ def __init__(self):
4833
def all(self):
4934
return self._headers
5035

36+
def get(self, key):
37+
return self._headers.get(key, None)
38+
5139
def persist_response_header(self, response, header):
5240
"""
5341
Persist header from response object.
@@ -68,24 +56,20 @@ def persist_headers(self, headers):
6856
class BaseClient:
6957
"""Base Client"""
7058

71-
def __init__(self, builder=None, session=None, settings=None, authenticator=None):
59+
def __init__(self, builder=None, session=None, settings=None, authenticator=None, headers=None):
7260
"""
7361
Initialize a Client
7462
7563
:param builder: Endpoint builder.
7664
:param ,optional session: Session.
77-
:param ,optional settings: Client Session Settings.
65+
:param pydantic.BaseModel,optional settings: Client Settings
7866
:param ,optional authenticator: Authenticator function.
67+
:param cterasdk.clients.base.Headers,optional headers: Headers Object
7968
"""
80-
self._headers = PersistentHeaders()
8169
self._authenticator = authenticator
8270
self._builder = builder
83-
84-
default_settings = ClientSessionSettings()
85-
if settings:
86-
default_settings.update(**settings)
87-
88-
self._session = session if session else async_requests.Session(default_settings, TraceSettings())
71+
self._session = session if session else async_requests.Session(get_configuration(settings))
72+
self._headers = headers if headers else Headers()
8973

9074
def clone(self, definition, builder=None, authenticator=None):
9175
"""
@@ -100,11 +84,12 @@ def clone(self, definition, builder=None, authenticator=None):
10084
self._session,
10185
None,
10286
authenticator if authenticator is not None else self._authenticator,
87+
self._headers
10388
)
10489

10590
@property
106-
def cookies(self):
107-
return CookieJar(self._session.cookies)
91+
def cookie_jar(self):
92+
return self._session.cookie_jar
10893

10994
@property
11095
def headers(self):

cterasdk/clients/clients.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,20 @@ def _webdav_headers(self, destination, overwrite):
9696

9797
class AsyncJSON(AsyncClient):
9898

99-
def __init__(self, builder=None, session=None, settings=None, authenticator=None):
100-
super().__init__(builder, session, settings, authenticator)
101-
self.headers.persist_headers({'Content-Type': 'application/json'})
102-
10399
async def get(self, path, **kwargs):
104100
response = await super().get(path, on_error=JSONHandler(), **kwargs)
105101
return await response.json()
106102

107103
async def put(self, path, data, **kwargs):
108-
response = await super().put(path, data, data_serializer=Serializers.JSON, on_error=JSONHandler(), **kwargs)
104+
response = await super().put(path, data, data_serializer=Serializers.JSON, headers={
105+
'Content-Type': 'application/json'
106+
}, on_error=JSONHandler(), **kwargs)
109107
return await response.json()
110108

111109
async def post(self, path, data, **kwargs):
112-
response = await super().post(path, data, data_serializer=Serializers.JSON, on_error=JSONHandler(), **kwargs)
110+
response = await super().post(path, data, data_serializer=Serializers.JSON, headers={
111+
'Content-Type': 'application/json'
112+
}, on_error=JSONHandler(), **kwargs)
113113
return await response.json()
114114

115115
async def delete(self, path, **kwargs):
@@ -305,20 +305,20 @@ def _webdav_headers(self, destination, overwrite):
305305
class XML(Client):
306306
"""XML Serializer and Deserializer"""
307307

308-
def __init__(self, builder=None, session=None, settings=None, authenticator=None):
309-
super().__init__(builder, session, settings, authenticator)
310-
self._type = {'Content-Type': 'text/plain'}
311-
312308
def get(self, path, **kwargs):
313309
response = super().get(path, on_error=XMLHandler(), **kwargs)
314310
return response.xml()
315311

316312
def put(self, path, data, **kwargs):
317-
response = super().put(path, data, data_serializer=Serializers.XML, headers=self._type, on_error=XMLHandler(), **kwargs)
313+
response = super().put(path, data, data_serializer=Serializers.XML, headers={
314+
'Content-Type': 'text/plain'
315+
}, on_error=XMLHandler(), **kwargs)
318316
return response.xml()
319317

320318
def post(self, path, data, **kwargs):
321-
response = super().post(path, data, data_serializer=Serializers.XML, headers=self._type, on_error=XMLHandler(), **kwargs)
319+
response = super().post(path, data, data_serializer=Serializers.XML, headers={
320+
'Content-Type': 'text/plain'
321+
}, on_error=XMLHandler(), **kwargs)
322322
return response.xml()
323323

324324
def form_data(self, path, data, **kwargs):

cterasdk/clients/decorators.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
def authenticated(execute_request):
1111
@functools.wraps(execute_request)
1212
def authenticate_then_execute(self, *args, **kwargs):
13-
if callable(self._authenticator) and self._authenticator(self._builder(args[0])): # pylint: disable=protected-access
13+
if (
14+
self.headers.get("Authorization") is not None
15+
) or (
16+
callable(self._authenticator) and self._authenticator(self._builder(args[0])) # pylint: disable=protected-access
17+
):
1418
try:
1519
return execute_request(self, *args, **kwargs)
1620
except SessionExpired:
1721
logger.error('Session expired.')
18-
self.cookies.clear()
22+
self.cookie_jar.clear()
1923
raise
2024
logger.error('Not logged in.')
2125
raise NotLoggedIn()

0 commit comments

Comments
 (0)