1717from metadata .generated .schema .entity .services .connections .database .sasConnection import (
1818 SASConnection ,
1919)
20+ from metadata .generated .schema .security .ssl .verifySSLConfig import VerifySSL
2021from metadata .ingestion .connections .source_api_client import TrackedREST
2122from metadata .ingestion .ometa .client import APIError , ClientConfig
2223from metadata .utils .helpers import clean_uri
2324from metadata .utils .logger import ingestion_logger
25+ from metadata .utils .ssl_registry import get_verify_ssl_fn
2426
2527logger = ingestion_logger ()
2628
29+ SAS_CLI_AUTH_HEADER = "Basic c2FzLmNsaTo="
30+
2731
2832class SASClient :
2933 """
@@ -33,13 +37,14 @@ class SASClient:
3337 def __init__ (self , config : SASConnection ):
3438 self .config : SASConnection = config
3539 self .auth_token = self .get_token (config .serverHost , config .username , config .password .get_secret_value ())
40+
3641 client_config : ClientConfig = ClientConfig (
3742 base_url = clean_uri (config .serverHost ),
3843 auth_header = "Authorization" ,
3944 auth_token = self .get_auth_token ,
4045 api_version = "" ,
4146 allow_redirects = True ,
42- verify = False ,
47+ verify = self . _get_verify () ,
4348 )
4449 self .client = TrackedREST (client_config , source_name = "sas" )
4550 # custom setting
@@ -50,6 +55,22 @@ def __init__(self, config: SASConnection):
5055 self .enable_dataflows = config .dataflows
5156 self .custom_filter_dataflows = config .dataflowsCustomFilter
5257
58+ def _get_verify (self ):
59+ """
60+ Helper to determine the SSL verification strategy
61+ """
62+ verify = True
63+ if self .config .verifySSL == VerifySSL .ignore :
64+ verify = False
65+ elif self .config .verifySSL == VerifySSL .no_ssl :
66+ verify = False
67+ elif self .config .verifySSL == VerifySSL .validate and self .config .sslConfig :
68+ try :
69+ verify = get_verify_ssl_fn (self .config .verifySSL )(self .config .sslConfig )
70+ except Exception : # pylint: disable=broad-except
71+ verify = True
72+ return verify
73+
5374 def check_connection (self ):
5475 """
5576 Check metadata connection to SAS
@@ -72,7 +93,7 @@ def get_instance(self, instance_id):
7293 }
7394 response = self .client .get (path = endpoint , headers = headers )
7495 if "error" in response .keys (): # noqa: SIM118
75- raise APIError (response ["error" ])
96+ raise APIError ({ "message" : response ["error" ]} )
7697 return response
7798
7899 def get_information_catalog_link (self , instance_id ):
@@ -99,7 +120,7 @@ def list_assets(self, assets):
99120 headers = {"Accept-Item" : "application/vnd.sas.metadata.instance.entity+json" }
100121 response = self .client .get (path = endpoint , headers = headers )
101122 if "error" in response .keys (): # noqa: SIM118
102- raise APIError (response ["error" ])
123+ raise APIError ({ "message" : response ["error" ]} )
103124 return response ["items" ]
104125
105126 def get_views (self , query ):
@@ -111,7 +132,7 @@ def get_views(self, query):
111132 logger .info (f"{ query } " )
112133 response = self .client .post (path = endpoint , data = query , headers = headers )
113134 if "error" in response .keys (): # noqa: SIM118
114- raise APIError (f" { response } " )
135+ raise APIError ({ "message" : "Error fetching views from SAS" } )
115136 return response
116137
117138 def get_data_source (self , endpoint ):
@@ -121,7 +142,7 @@ def get_data_source(self, endpoint):
121142 response = self .client .get (path = endpoint , headers = headers )
122143 logger .info (f"{ response } " )
123144 if "error" in response .keys (): # noqa: SIM118
124- raise APIError (response ["error" ])
145+ raise APIError ({ "message" : response ["error" ]} )
125146 return response
126147
127148 def get_report_link (self , resource , uri ):
@@ -136,7 +157,7 @@ def get_report_relationship(self, report_id):
136157 endpoint = f"reports/commons/relationships/reports/{ report_id } "
137158 response = self .client .get (endpoint )
138159 if "error" in response .keys (): # noqa: SIM118
139- raise APIError (response ["error" ])
160+ raise APIError ({ "message" : response ["error" ]} )
140161 dependencies = []
141162 for item in response ["items" ]:
142163 if item ["type" ] == "Dependent" :
@@ -146,14 +167,14 @@ def get_report_relationship(self, report_id):
146167 def get_resource (self , endpoint ):
147168 response = self .client .get (endpoint )
148169 if "error" in response .keys (): # noqa: SIM118
149- raise APIError (response ["error" ])
170+ raise APIError ({ "message" : response ["error" ]} )
150171 return response
151172
152173 def get_instances_with_param (self , data ):
153174 endpoint = f"catalog/instances?{ data } "
154175 response = self .client .get (endpoint )
155176 if "error" in response .keys (): # noqa: SIM118
156- raise APIError (response ["error" ])
177+ raise APIError ({ "message" : response ["error" ]} )
157178 return response ["items" ]
158179
159180 def get_auth_token (self ):
@@ -164,8 +185,30 @@ def get_token(self, base_url, user, password):
164185 payload = {"grant_type" : "password" , "username" : user , "password" : password }
165186 headers = {
166187 "Content-type" : "application/x-www-form-urlencoded" ,
167- "Authorization" : "Basic c2FzLmNsaTo=" ,
188+ "Authorization" : SAS_CLI_AUTH_HEADER ,
168189 }
169190 url = base_url + endpoint
170- response = requests .request ("POST" , url , headers = headers , data = payload , verify = False , timeout = 10 )
171- return response .json ()["access_token" ]
191+
192+ response = requests .request (
193+ "POST" ,
194+ url ,
195+ headers = headers ,
196+ data = payload ,
197+ verify = self ._get_verify (),
198+ timeout = 10 ,
199+ )
200+ logger .debug (
201+ "Token request for user: %s completed with status: %s" ,
202+ user ,
203+ response .status_code ,
204+ )
205+ response .raise_for_status ()
206+ try :
207+ body = response .json ()
208+ except ValueError as exc :
209+ raise RuntimeError (f"SAS token endpoint returned non-JSON response (HTTP { response .status_code } )" ) from exc
210+
211+ token = body .get ("access_token" )
212+ if not token :
213+ raise RuntimeError (f"Failed to retrieve access_token from SAS (HTTP { response .status_code } )" )
214+ return token
0 commit comments