jborean93 / smbprotocol

Python SMBv2 and v3 Client
MIT License
320 stars 74 forks source link

Authentication with Delegated Credentials #205

Open iekanat opened 1 year ago

iekanat commented 1 year ago

We use delegated credentials in our jupyter server, I would like to be able to use the cached credentials to be able to authenticate with smb server.

Other methods seem to work fine (e.g.: !smbclient) but smbclient protocol does not seem to handle this use case. Is there any guidance on this?

jborean93 commented 1 year ago

If you have a credential in the ccache then this library should be able to use those credentials if no username/password is set. I use it all the time to do things like smbclient.open_file(path, mode='r') without having to also set the credentials.

For this to work you do need the optional Kerberos Python libraries to be installed which on Linux is currently gssapi and krb5. You can always reference the correct ones by doing pip install smbprotocol[kerberos].

The part I'm not played around with is delegated credentials. If these delegated credentials are in the ccache and you can do things like kvno cifs/host.realm.com@REALM.COM then smbclient should just be able to use those.

iekanat commented 1 year ago

Thanks for the quick response.

The situation as I understand is that delegated credentials is supported in some packages (such as smbclient) but not others (such as kvno).

  1. When I use smbclient -k //drive/share -c ls I can see the files.
  2. When I klist -A I can see the cifs related credential.

11/29/22 10:37:29 11/29/22 19:30:44 cifs/host.realm.com@REALM.COM for client delegatingserver$@REALM.COM

  1. when I use kvno cifs/host.realm.com@REALM.COM I get:

kvno: Matching credential not found (filename: /tmp/krb5cc_12345) while getting credentials for cifs/host.realm.com@REALM.COM

I think it is the libraries that are different between smbclient and kvno.

When I issue: ldd /usr/bin/smbclient

I get:

        libsmbconf.so.0 => /lib/x86_64-linux-gnu/libsmbconf.so.0 (0x00007f0cdfc41000)
.
.
.
.
        libkrb5.so.26 => /lib/x86_64-linux-gnu/libkrb5.so.26 (0x00007f3f13509000)
.
.
.

When I issue: ldd kvno

I get:

.
.
        libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007f7f362fc000)
.
.

I hope that was a bit helpful.

jborean93 commented 1 year ago

Are you able to share your full workflow with smbclient? How are you getting a delegated credential for it to use?

The kvno command is from MIT krb5 essentially getting a service ticket for the SPN requested. It needs a TGT to send to KDC for it to get that ticket for that SPN. The error you got back indicates there is no credential available in the ccache that it can use to get the ticket. This essentially replicates the first phase of Kerberos authentication that this library also does.

I think it is the libraries that are different between smbclient and kvno.

Makes some sense, the default Kerberos library used on most Linux distributions is MIT krb5 while Samba usually compiles against their own fork of Heimdal. If you search libkrb5.so.26 you'll see that it is distributed by Heimdal packages whereas libkrb5.so.3 is from MIT krb5.

Now it is perfectly possible to have the Kerberos dependencies of this library compile against the Heimdal libs instead of MIT krb5 but the method of doing so depends on a few things. Currently the Python modules are looking up krb5-config in the path and using the information it returns to find what libkrb5 to link against. Because MIT is most likely the first one in the PATH it will select that.

To get it to use Heimdal instead you'll need to ensure that the Heimdal krb5-config is used instead. Judging by your paths it seems like you are on a Debian/Ubuntu based distribution so you can install the heimdal-multidev which provides the Heimdal dev packages but in a way that won't conflict with MIT krb5. Once installed you can run the following to reinstall the Kerberos libraries against Heimdal:

python3 -m venv smb-test
source smb-test/bin/activate
python -m pip install -U pip setuptools
KRB5_KRB5CONFIG=/usr/bin/krb5-config.heimdal GSSAPI_KRB5CONFIG=$KRB5_KRB5CONFIG python -m pip install smbprotocol[kerberos] --no-cache-dir

Note: I'm using a venv to ensure I have the latest pip and setuptools and a way to blow away the changes without affecting the system. The env vars should work for a normal pip install with these libs but mileage may vary based on your pip/setuptools version. Things may also fail to install depending on the compiler. Using Heimdal with this library is definitely an edge case and not the standard scenario.

You can verify if it compiled against Heimdal instead of MIT by checking the paths on the following:

ldd "$(python -c 'import gssapi; print(gssapi.raw.sec_contexts.__file__)')"
ldd "$(python -c 'import krb5; print(krb5._context.__file__)')"

There's no guarantee that this will automatically pick up the cached credential though. Maybe it's a Heimdal specific feature or maybe Samba's smbclient is doing something special that I'm not aware of. Knowing your workflow might help me to replicate it and potentially see what is happening.

iekanat commented 1 year ago

Thanks for the tip. I will work on it and get back here. I hope it will help future generations :D