77
88.. moduleauthor:: Daniel Carrion <[email protected] > 99.. moduleauthor:: Alberto Romeu <[email protected] > 10+ .. moduleauthor:: Juan Ignacio Sánchez <[email protected] > 1011
1112
1213"""
1617import sys
1718import warnings
1819
19- from pyrestcli .auth import BaseAuthClient
20+ from pyrestcli .auth import BaseAuthClient , BasicAuthClient
2021
2122from .exceptions import CartoException
2223
2627 from urlparse import urlparse
2728
2829
29- class APIKeyAuthClient (BaseAuthClient ):
30+ class _UsernameGetter :
31+ def get_user_name (self , base_url ):
32+ try :
33+ url_info = urlparse (base_url )
34+ # On-Prem:
35+ # /user/<username>
36+ m = re .search ('^/user/([^/]+)/.*$' , url_info .path )
37+ if m is None :
38+ # Cloud personal account (org and standalone)
39+ # <username>.carto.com
40+ netloc = url_info .netloc
41+ if netloc .startswith ('www.' ):
42+ netloc = netloc .split ('www.' )[1 ]
43+ m = re .search ('^(.*?)\..*' , netloc )
44+ return m .group (1 )
45+ except Exception :
46+ raise CartoException (_ ("Could not find a valid user_name in the " +
47+ "base URL provided. Please check that the" +
48+ "URL is one of " +
49+ "'https://{user_name}.carto.com', " +
50+ "'https://carto.com/user/{user_name}' " +
51+ "or a similar one based on your domain" ))
52+
53+
54+ class _BaseUrlChecker :
55+ def check_base_url (self , base_url ):
56+ if not base_url .startswith ("https" ):
57+ warnings .warn ("You are using unencrypted API key \
58+ authentication!!!" )
59+ # Make sure there is a trailing / for urljoin
60+ if not base_url .endswith ('/' ):
61+ base_url += '/'
62+
63+ return base_url
64+
65+
66+ class APIKeyAuthClient (_UsernameGetter , _BaseUrlChecker , BaseAuthClient ):
3067 """
3168 This class provides you with authenticated access to CARTO's APIs using
3269 your API key.
@@ -48,17 +85,9 @@ def __init__(self, base_url, api_key, organization=None, session=None):
4885
4986 :return:
5087 """
51- if not base_url .startswith ("https" ):
52- warnings .warn ("You are using unencrypted API key \
53- authentication!!!" )
54-
5588 self .organization = organization
5689 self .api_key = api_key
57-
58- # Make sure there is a trailing / for urljoin
59- if not base_url .endswith ('/' ):
60- base_url += '/'
61-
90+ base_url = self .check_base_url (base_url )
6291 self .username = self .get_user_name (base_url )
6392
6493 super (APIKeyAuthClient , self ).__init__ (base_url , session = session )
@@ -88,28 +117,6 @@ def send(self, relative_path, http_method, **requests_args):
88117 except Exception as e :
89118 raise CartoException (e )
90119
91- def get_user_name (self , base_url ):
92- try :
93- url_info = urlparse (base_url )
94- # On-Prem:
95- # /user/<username>
96- m = re .search ('^/user/([^/]+)/.*$' , url_info .path )
97- if m is None :
98- # Cloud personal account (org and standalone)
99- # <username>.carto.com
100- netloc = url_info .netloc
101- if netloc .startswith ('www.' ):
102- netloc = netloc .split ('www.' )[1 ]
103- m = re .search ('^(.*?)\..*' , netloc )
104- return m .group (1 )
105- except Exception :
106- raise CartoException (_ ("Could not find a valid user_name in the " +
107- "base URL provided. Please check that the" +
108- "URL is one of " +
109- "'https://{user_name}.carto.com', " +
110- "'https://carto.com/user/{user_name}' " +
111- "or a similar one based on your domain" ))
112-
113120 def prepare_send (self , http_method , ** requests_args ):
114121 http_method = http_method .lower ()
115122 if (http_method in ['post' , 'put' ]) and "json" in requests_args :
@@ -169,4 +176,51 @@ def send(self, relative_path, http_method, **requests_args):
169176 http_method ,
170177 ** requests_args )
171178 except Exception as e :
172- raise CartoException (e )
179+ raise CartoException (e )
180+
181+
182+ class AuthAPIClient (_UsernameGetter , _BaseUrlChecker , BasicAuthClient ):
183+ """
184+ This class provides you with authenticated access to CARTO's APIs using
185+ your API key at Basic authentication header, as provided by Auth API.
186+
187+ Auth API is still under development. You might want to take a look at
188+ APIKeyAuthClient for missing features or an stable API.
189+
190+ You can find your API key by clicking on the API key section of the user
191+ dropdown menu
192+ """
193+
194+ def __init__ (self , base_url , api_key , organization = None , session = None ):
195+ """
196+ Init method
197+
198+ :param base_url: Base URL. API endpoint paths will always be relative
199+ to this URL
200+ :param api_key: API key
201+ :param organization: For enterprise users, organization user belongs to
202+ :param session: requests' session object
203+ :type api_key: str
204+ :type organization: str
205+
206+ :return:
207+ """
208+ self .organization = organization
209+ self .api_key = api_key
210+ base_url = self .check_base_url (base_url )
211+ self .username = self .get_user_name (base_url )
212+
213+ super (AuthAPIClient , self ).__init__ (self .username , api_key , base_url , session = session )
214+
215+ def is_valid_api_key (self ):
216+ """
217+ Checks validity. Right now, an API key is considered valid if it
218+ can list user API keys and the result contains that API key.
219+ This might change in the future.
220+
221+ :return: True if the API key is considered valid for current user.
222+ """
223+ res = self .send ('/api/v3/api_keys' , 'get' )
224+ return \
225+ res .ok and \
226+ self .api_key in (ak ['token' ] for ak in res .json ()['result' ])
0 commit comments