sassoftware / python-swat

The SAS Scripting Wrapper for Analytics Transfer (SWAT) package is the Python client to SAS Cloud Analytic Services (CAS). It allows users to execute CAS actions and process the results all from Python.
Other
147 stars 63 forks source link

swat: cas connection error (Incorrect Certificate 807ff008) #67

Closed pwnaoj closed 4 years ago

pwnaoj commented 4 years ago

Hi,

I have the following connection error:

ERROR: The TCP/IP negClientSSL support routine failed with status 807ff008.
ERROR: Encryption run-time execution error
ERROR: Failed to connect to host 'my-ip-cas-server', port 5570.

My Python version is 3.7 and SWAT version is 1.6.0. This is my code:

import swat

conn = swat.CAS('my-ip-cas-server', 5570, 'my-user', 'my-pass')

According to the SWAT documentation I am using an erroneous certificate, what I don't know is where I find the certificate path, I don't even know what the certificates I have? Where can I find the certificates?

Thanks in advance.

kesmit13 commented 4 years ago

It really depends on your server installation. If you used the default certificates for the server, they will be installed in /opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/. You need to copy the certificate to the client. Try using trustedcerts.pem first. If that doesn't, work you can try vault-ca.crt.

pwnaoj commented 4 years ago

@kesmit13 , thanks for your answer.

I checked the server configuration and found the following:

CAS_CLIENT_SSL_CA_LIST | /opt/sas/viya/config/etc/cas/default/../../SASSecurityCertificateFramework/cacerts/trustedcerts.pem

Now the following questions arise:

  1. How can I access that route to obtain the certificate?
  2. I am using Windows 10 as an operating system, then I understand that I must add the certificate to Window’s certificate stores. Is it necessary then to add the environment variable?
kesmit13 commented 4 years ago

On Windows, you won't need the environment variable. Unfortunately, Windows does work a bit differently because of this. If you use the REST interface to CAS, you would need the environment variable since the Python requests package doesn't support the certificate store. However, you are currently using the binary protocol which does go through the certificate store.

pwnaoj commented 4 years ago

I have tried with this

import swat
import os

os.environ['CAS_CLIENT_SSL_CA_LIST'] = 'C:/Users/my-user/trustedcerts.pem'

#REST
conn = swat.CAS('https://my-host:443/cas-shared-default-http/', userid='my-user', password='my-password')

but still I get the following error:

SWATError: Unable to connect to any URL: https://my-host:443/cas-shared-default-http/

kesmit13 commented 4 years ago

Can you change userid= to username= and see what happens? That's an error in the doc that was fixed (just yesterday), but hasn't made it out to the published doc yet.

pwnaoj commented 4 years ago

I tried your suggestion but the same error appears, i.e. ,

SWATError: Unable to connect to any URL: https://my-host:443/cas-shared-default-http/

kesmit13 commented 4 years ago

Not sure what the issue is yet, but try this: install the vault-ca.crt to your certificate store and try the binary protocol (5570) again. If that still doesn't work, try the httpproxy-microservices_1-ca.crt in your environment variable with the REST interface.

There are some debugging logs that you can turn on for the REST client as well:

swat.options.cas.debug.requests = True
swat.options.cas.debug.request_bodies = True
swat.options.cas.debug.responses = True
pwnaoj commented 4 years ago

I made progress. I tried your suggestion to import the vault-ca.crt certificate and it seems that I have already established a connection to the server, but now the error is authentication. I have clearly checked the credentials thoroughly and everything is fine.

This is the error:

ERROR: Connection failed. Server returned: SAS Logon Manager authentication failed: Access denied.
---------------------------------------------------------------------------
SystemError                               Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\connection.py in __init__(self, hostname, port, username, password, session, locale, nworkers, name, authinfo, protocol, **kwargs)
    302                 else:
--> 303                     self._sw_connection = clib.SW_CASConnection(*params)
    304 

C:\ProgramData\Anaconda3\lib\site-packages\swat\clib.py in SW_CASConnection(*args, **kwargs)
    102         _import_pyswat()
--> 103     return _pyswat.SW_CASConnection(*args, **kwargs)
    104 

SystemError: <class 'py37swat.SW_CASConnection'> returned NULL without setting an error

During handling of the above exception, another exception occurred:

SWATError                                 Traceback (most recent call last)
<ipython-input-5-159751a86f34> in <module>
      6 
      7 #Binary
----> 8 conn = swat.CAS('my-ip-cas-server', 5570, 'my-user', 'my-pass')
      9 #out = conn.serverstatus()

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\connection.py in __init__(self, hostname, port, username, password, session, locale, nworkers, name, authinfo, protocol, **kwargs)
    308 
    309         except SystemError:
--> 310             raise SWATError(self._sw_error.getLastErrorMessage())
    311 
    312         # Set up index origin for error messages

SWATError: Could not connect to 'my-ip-cas-server' on port 5570.
kesmit13 commented 4 years ago

Can you try to log into the SASLogon directly using the URL https:///SASLogon? It just looks like your username and password are invalid.

pwnaoj commented 4 years ago

Yes, I can log into the SASLogon through the URL you specify.

kesmit13 commented 4 years ago

And that same username and password don't work with swat.CAS(...)?

pwnaoj commented 4 years ago

That is correct, it does not work.

kesmit13 commented 4 years ago

Try setting an environment variable CASCLIENTDEBUG=1 and see if it gives you any extra information.

pwnaoj commented 4 years ago

OK, this is what i get:

NOTE: Client is using userid=my-user, password=***
NOTE: Client is using the userpass identity provider
NOTE: Sent challenge length 106
NOTE: Received response length 50
NOTE: Got disposition, severity 2, reason 4, message Authentication failed: Access denied.
kesmit13 commented 4 years ago

You wouldn't happen to have any backslashes in your username or password?

pwnaoj commented 4 years ago

I have letters, numbers and hashtags on my password.

pwnaoj commented 4 years ago

Should I change my password?

Update: I tried to perform the authentication using an authinfo file and I get this

NOTE: HOMEDRIVE: C:
NOTE: HOMEPATH: \Users\my-user
NOTE: Process owner identity is: my-company/my-user
NOTE: Reading authinfo file: C:/Users/my-user/_authinfo.txt
NOTE: Matching host: my-host-ip
NOTE: Matching port: 5570
NOTE: Matching user: NONE
NOTE: Using authinfo host definition: host my-host-ip port 5570 user my-user password ************
NOTE: Client is using userid=my-user, password=***
NOTE: Client is using the userpass identity provider
NOTE: Sent challenge length 106
NOTE: Received response length 68
NOTE: Got disposition, severity 2, reason 4, message SAS Logon Manager authentication failed: Access denied.
ERROR: Connection failed. Server returned: SAS Logon Manager authentication failed: Access denied.
kesmit13 commented 4 years ago

The "Matching user: NONE" simply means you didn't specify a username in swat.CAS(...). That just means that any username in the authinfo file is ok. I'm still not sure what is going on in your case and I've been asking around. I think we've done all of the digging we can on the client side. Do you have access to the server logs to see anything that may be coming up there?

kesmit13 commented 4 years ago

Just to eliminate any possible issues with characters in your password, you could try this. Go to https://hostname/SASStudioV/ and encode your password using:

proc pwencode in='<your password>'; run;

Then use the resulting string as your password in swat.CAS(...).

pwnaoj commented 4 years ago

I'm not sure if this is part of the server log, otherwise I will continue searching for the correct log.

started, Startup command-line is: /opt/sas/spre/home/SASFoundation/sasexe/sas -autoexec /opt/sas/viya/config/etc/evmsvrops/autoexec.sas -logconfigloc /opt/sas/viya/config/etc/evmsvrops/logconfig.arm.xml -sysin /opt/sas/viya/home/lib/evmsvrops/SASCode/etl_driver.sas
Feb 10 16:15:20 olsrvsas01 _tk4aunxf_: INFO  [00000004] sas - SAH239999I Batch, State, stopped
Feb 10 16:20:01 olsrvsas01 systemd: Started Session 2744 of user root.
Feb 10 16:20:01 olsrvsas01 systemd: Starting Session 2744 of user root.
Feb 10 16:20:33 olsrvsas01 _tk4aunxf_: INFO  [00000004] sas - SAH231999I Batch, State, started, Startup command-line is: /opt/sas/spre/home/SASFoundation/sasexe/sas -autoexec /opt/sas/viya/config/etc/evmsvrops/autoexec.sas -logconfigloc /opt/sas/viya/config/etc/evmsvrops/logconfig.arm.xml -sysin /opt/sas/viya/home/lib/evmsvrops/SASCode/etl_driver.sas
Feb 10 16:20:34 olsrvsas01 _tk4aunxf_: INFO  [00000004] sas - SAH239999I Batch, State, stopped
Feb 10 16:22:01 olsrvsas01 systemd: Starting System Security Services Daemon...
Feb 10 16:22:02 olsrvsas01 sssd: Cannot read config file /etc/sssd/sssd.conf. Please check that the file is accessible only by the owner and owned by root.root.
Feb 10 16:22:02 olsrvsas01 systemd: sssd.service: main process exited, code=exited, status=4/NOPERMISSION
Feb 10 16:22:02 olsrvsas01 systemd: Failed to start System Security Services Daemon.
Feb 10 16:22:02 olsrvsas01 systemd: Unit sssd.service entered failed state.
Feb 10 16:22:02 olsrvsas01 systemd: sssd.service failed.
Feb 10 16:22:12 olsrvsas01 systemd: Configuration file /etc/systemd/system/sas-viya-sasdatasvrc-postgres-node0.service is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.
Feb 10 16:22:12 olsrvsas01 systemd: Configuration file /etc/systemd/system/sa

Regarding the other suggestion this is what I get when executing the suggested code, but I don't know what is the new password that I must specify in swat.CAS(..)

1     OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
75    
76    proc pwencode in=XXXXXXXXXXXX; run;
{SAS002}XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NOTE: PROCEDIMIENTO PWENCODE used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

77    
78    OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
91    
kesmit13 commented 4 years ago

You would use the "{SAS02}ABCDEF..." part.

kesmit13 commented 4 years ago

Here's another thing you can check. The following will show you the details of the CAS configuration. Maybe something there will help.

https://hostname/SASEnvironmentManager/ -> "servers"-> RMB "cas-shared-default"-> "Configuration"-> "CAS Configuration" tab

pwnaoj commented 4 years ago

I tried your suggestion but I still get the same error. On the other hand, what specific requirements are needed from the Linux server side and / or in the SAS configuration? With that information we may be able to find something useful from the server side which is possibly not allowing authentication.

kesmit13 commented 4 years ago

Did you look into the SASEnvironmentManager CAS configuration?

pwnaoj commented 4 years ago

Sorry for copying and pasting all this information ... but I really don't know what I'm looking for. I hope it is useful for solving the issue.

appTag |   | default
caslib |   | default
cfg |   | default
cfgname | viya_default | Command Line
cfgpath | /opt/sas/viya/config/etc/cas/default | Command Line
cmplib |   | default
cmpopt |   | default
collate | UCA | default
colocation | COLOC_UNSPECIFIED | default
command | START | Command Line
controlpid | 9337 | Internal/Computed
cpushares | max=100000,min=0,val=0 | default
dataStepFmtErr | true | default
dataStepMsgSumLevel | ALL | default
dataStepReplaceTable | true | default
dchostnameresolution |   | default
dcsslcertiss |   | default
dcsslcertloc | /opt/sas/viya/config/etc/SASSecurityCertificateFramework/tls/certs/cas/shared/default/sas_encrypted.crt | File
dcsslcertserial |   | default
dcsslcertsubj |   | default
dcsslpkcs12loc |   | default
dcsslpkcs12pass |   | default
dcsslpvtkeyloc | /opt/sas/viya/config/etc/SASSecurityCertificateFramework/private/cas/shared/default/sas_encrypted.key | File
dcsslpvtkeypass | **** | Internal/Computed
dcsslpvtkeypassloc | /opt/sas/viya/config/etc/SASSecurityCertificateFramework/private/cas/shared/default/encryption.key | File
dctcpmencrypt | OPTIONAL | File
dctcpmencryptalgorithm |   | default
dqLocale |   | default
dqQKBRepoLoc | ReferenceData | default
dqSetupLoc |   | default
elastic | false | default
elasticssl | false | default
eventds |   | default
executable | /opt/sas/viya/home/SASFoundation/utilities/bin/cas | Command Line
fmtErr |   | default
fmtsearch | SASSuppliedFormats | Set
gcport | max=65535,min=0,val=34372 | Internal/Computed
hdfsuserloc | /user/%USER | File
hostknownby |   | default
httpport | max=65535,min=0,val=8777 | File
httpportmax | max=65535,min=0,val=8778 | default
id | 0 | default
initialbackups | max=1,min=-1,val=0 | Internal/Computed
initialworkers | max=32767,min=-1,val=0 | Internal/Computed
install | /opt/sas/viya/home/SASFoundation | Environment
intervalds |   | default
join |   | default
jreoptions | (-Xms256m -Xmx1024m -Djavax.net.ssl.trustStore=/opt/sas/viya/home/SASFoundation/../../config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.jks -Dlog4j.configuration=/opt/sas/viya/home/SASFoundation/misc/tkjava/sas.log4j.properties -Dfile.encoding=UTF-8 -Djava.class.path=/opt/sas/viya/home/SASFoundation/lib/base/base-tkjni.jar) | File
keyfile |   | default
lifetime | 0 | default
links |   |  
locale | en_US | default
logcfgloc | /opt/sas/viya/config/etc/cas/default/logconfig.xml | File
logFlushTime | max=86400,min=-1,val=100 | default
machinelist | /opt/sas/viya/config/etc/cas/default/cas.hosts | File
maxcores |   | default
maxsessions | max=100000,min=0,val=5000 | default
maxTableMem | 16777216 | default
memorysize | 0 | default
messageLevel | all | default
metrics | false | default
mode | SMP | File
node |   | default
nWorkers | max=5000,min=0,val=0 | default
oauthsigningcertificate |   | default
oauthsigningkey |   | default
onelog | false | default
permstore | /opt/sas/viya/config/etc/cas/default/permstore | Command Line
port | max=65535,min=0,val=5570 | File
privacyStatement |   | default
provlist | oauth.ext | File
removeNodeCancelTimeout | max=1800,min=0,val=120 | default
removeNodeKillTimeout | max=1800,min=0,val=15 | default
resolveworkeraddress | true | default
role | CONTROLLER | Command Line
servicesBaseUrl | https://my-host::8084/ | File
session |   | default
startup |   | default
startupdir |   | default
subsetSessionCopies | max=5000,min=0,val=0 | default
tag |   | default
tenantid |   | default
timeout | max=31536000,min=0,val=60 | default
timeZone |   | default
userloc | /opt/sas/viya/config/data/cas/default/casuserlibraries/%USER | Command Line
useyarn | false | default
pwnaoj commented 4 years ago

I tried something new, specifying the session, and this is what I get:

import os

os.environ['CASCLIENTDEBUG'] = '1'

import swat

#Binary
conn = swat.CAS('my-cas-ip', 5570, session='af1aee09-9f44-994f-8c56-757db22fa032', authinfo='C:/Users/my-user/_authinfo.txt')
NOTE: HOMEDRIVE: C:
NOTE: HOMEPATH: \Users\my-user
NOTE: Process owner identity is: my-company/my-user
NOTE: Reading authinfo file: C:/Users/my-user/_authinfo.txt
NOTE: Matching host: my-cas-ip
NOTE: Matching port: 5570
NOTE: Matching user: NONE
NOTE: Using authinfo host definition: host 10.140.29.64 port 5570 user my-company\my-user password ********************************
NOTE: Client is using userid=my-company\my-user, password=***
NOTE: Client is using the userpass identity provider
NOTE: Sent challenge length 154
NOTE: Received response length 51
NOTE: User my-user connected to CAS using user/pass.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-3951e4da197c> in <module>
     10 
     11 #Binary
---> 12 conn = swat.CAS('10.140.29.64', 5570, session='af1aee09-9f44-994f-8c56-757db22fa032', authinfo='C:/Users/my-user/_authinfo.txt')
     13 #out = conn.serverstatus()

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\connection.py in __init__(self, hostname, port, username, password, session, locale, nworkers, name, authinfo, protocol, **kwargs)
    346                                            showhidden=True,
    347                                            _messagelevel='error',
--> 348                                            _apptag='UI').items():
    349             self._actionset_classes[asname.lower()] = None
    350             for actname in value['name']:

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\connection.py in retrieve(self, _name_, **kwargs)
   1697             signature = self._invoke_with_signature(a2n(_name_), **kwargs)
   1698             results = self._get_results(getnext(self, datamsghandler=datamsghandler),
-> 1699                                         responsefunc=responsefunc, resultfunc=resultfunc)
   1700         except SWATCASActionRetry:
   1701             signature = self._invoke_with_signature(a2n(_name_), **kwargs)

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\connection.py in _get_results(self, riter, responsefunc, resultfunc)
   1775                 castable = None
   1776 
-> 1777                 for key, value in response:
   1778 
   1779                     if resultfunc is not None:

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\response.py in __iter__(self)
    331             elif isinstance(key, binary_types):
    332                 key = a2u(key, 'utf-8')
--> 333             yield key, cas2py(_sw_result, self.soptions, connection=self._connection)
    334             _sw_result = errorcheck(self._sw_response.getNextResult(), self._sw_response)
    335 

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\transformers.py in cas2py(_sw_value, soptions, connection)
    482                               connection, ctb2tabular,
    483                               base64.b64decode, casdt.cas2python_datetime,
--> 484                               casdt.cas2python_date, casdt.cas2python_time)
    485 #   return CAS2PY[errorcheck(_sw_value.getType(),
    486 #                            _sw_value)](_sw_value, soptions, errorcheck, connection)

C:\ProgramData\Anaconda3\lib\site-packages\swat\cas\transformers.py in ctb2tabular(_sw_table, soptions, connection)
    380                                bygroup_as_index=optbyidx,
    381                                bygroup_formatted_suffix=optbysfx,
--> 382                                bygroup_collision_suffix=optbycolsfx)
    383 
    384     # Add an index as needed

C:\ProgramData\Anaconda3\lib\site-packages\swat\dataframe.py in reshape_bygroups(self, bygroup_columns, bygroup_as_index, bygroup_formatted_suffix, bygroup_collision_suffix)
    826         '''
    827         # Make a copy of the DataFrame
--> 828         dframe = self[self.columns]
    829         dframe.colinfo = dframe.colinfo.copy()
    830         dframe.attrs = dframe.attrs.copy()

C:\ProgramData\Anaconda3\lib\site-packages\swat\dataframe.py in __getitem__(self, *args, **kwargs)
    497 
    498         '''
--> 499         result = super(SASDataFrame, self).__getitem__(*args, **kwargs)
    500 
    501         if isinstance(result, SASDataFrame):

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
   2810             indexer = np.where(indexer)[0]
   2811 
-> 2812         data = self._take_with_is_copy(indexer, axis=1)
   2813 
   2814         if is_single_key:

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py in _take_with_is_copy(self, indices, axis, **kwargs)
   3406         See the docstring of `take` for full explanation of the parameters.
   3407         """
-> 3408         result = self.take(indices=indices, axis=axis, **kwargs)
   3409         # Maybe set copy if we didn't actually change the index.
   3410         if not result._get_axis(axis).equals(self._get_axis(axis)):

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py in take(self, indices, axis, is_copy, **kwargs)
   3394             indices, axis=self._get_block_manager_axis(axis), verify=True
   3395         )
-> 3396         return self._constructor(new_data).__finalize__(self)
   3397 
   3398     def _take_with_is_copy(

C:\ProgramData\Anaconda3\lib\site-packages\swat\dataframe.py in __init__(self, data, index, columns, dtype, copy, name, label, title, formatter, attrs, colinfo)
    416         self.title = a2u(title)
    417         # TODO: Should attrs be walked and converted to unicode?
--> 418         self.attrs = attrs
    419         if self.attrs is None:
    420             self.attrs = {}

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py in __setattr__(self, name, value)
   5284         try:
   5285             object.__getattribute__(self, name)
-> 5286             return object.__setattr__(self, name, value)
   5287         except AttributeError:
   5288             pass

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py in attrs(self, value)
    251     @attrs.setter
    252     def attrs(self, value: Mapping[Optional[Hashable], Any]) -> None:
--> 253         self._attrs = dict(value)
    254 
    255     def _validate_dtype(self, dtype):

TypeError: 'NoneType' object is not iterable
kesmit13 commented 4 years ago

Brilliant! You are connected now! However, you are hitting a new issue. You must have pandas v1.0.0 installed which changed some APIs and is broken in your version of SWAT. Luckily, I just released a new version yesterday (v1.6.1) which is compatible with pandas v1.0.0, so if you install that you should be up and running.

pwnaoj commented 4 years ago

Finally I was able to connect to the CAS server through the session id that is generated when I log in from SASLogon ... but I would like to know if I necessarily require the session id to connect, since in the swat documentation it is not necessary, and if it is So, how could I automate this process, since it is very exhausting to copy the session id to the code every time I want to establish the connection to the CAS server.

kesmit13 commented 4 years ago

Having to specify an existing session ID is definitely not a normal procedure. I think we might be better off moving this into SAS tech support so that we aren't asking for more sensitive information in a public forum. This appears to be a server-side issue and I'm not a server-side expert, so it would be better to get those people involved in debugging this issue.

Here is the link for opening a SAS tech support issue. I've already talked to them about this issue, so they are looking out for it.

https://support.sas.com/en/technical-support/contact-sas.html

pwnaoj commented 4 years ago

Thank you for your help in each comment, I am totally grateful to you.

kesmit13 commented 4 years ago

No problem. Once you get it sorted out, just let me know and we can post the solution here (if needed) and close the issue.

pwnaoj commented 4 years ago

I checked the log in more detail and found this:

ERROR [00690645] cas local MAIN NoUser  [tkclscommon.c:215] - pam_authenticate failed: User not known to the underlying authentication module (10).
ERROR [00690645] cas local MAIN NoUser  [tkidentext.c:684] - Access denied.
ERROR [00690645] cas local MAIN NoUser  [tkident.c:1232] - Authentication failed for user 'my-company\my-user'.
[00690645] cas local MAIN NoUser  [tkident.c:1233] - Access denied. 

I have searched for information about it and it seems to be related to a certain linux server configuration. I'm still waiting for a response from SAS Support.

gygabyte017 commented 4 years ago

Did you find the solution? Are you using a LDAP credential? It appears that if your authentication provider is LDAP, i.e. the user is authenticated against a domain, and such a user IS NOT a unix user, the connection with swat fails. The LDAP user should somehow be mapped with an existing unix user, I don't know if that was your case.

kesmit13 commented 4 years ago

I'm going to assume this was handled by SAS Tech Support. It appears to be a server-side issue.