diff --git a/README.md b/README.md index f7a9b77..bff69d2 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,30 @@ print(result["output"]) print(result["err"]) ``` +## For remote access using Kerberos authentication +Kerberos requires a valid ticket on the local host before attempting a connection. To create a Ticket Granting Ticket (TGT), run: +```bash +kinit msarkis@ICR.AC.UK +``` +* Replace msarkis with your actual username. +* This generates a Ticket Granting Ticket (TGT) with a default validity of 10 hours. +* You will need to renew or recreate the ticket once it expires. + +``` +from pyalma import KerberosClient +kerberos_ssh = KerberosClient(server="your_server", username="your_username") +result = kerberos_ssh.run_cmd("ls -l") +print(result["output"]) +print(result["err"]) +``` + +Notes: + +* This authentication method only works with servers that support Kerberos. +* At ICR, a test server sjane is available for experimenting. +* When you SSH using gssapi-with-mic, the client automatically requests a service ticket for host/sjane@ICR.AC.UK from the Kerberos Key Distribution Center (KDC). + + ## For local access, from within python ``` from pyalma import LocalFileReader diff --git a/pyalma/__init__.py b/pyalma/__init__.py index d25aa87..f35bdde 100644 --- a/pyalma/__init__.py +++ b/pyalma/__init__.py @@ -3,6 +3,7 @@ from .local import LocalFileReader from .ssh import SshClient from .securessh import SecureSshClient +from .kerberos import KerberosClient from .pdfreader import read_pdf_to_dataframe,read_pdf_as_text from importlib.metadata import version, PackageNotFoundError from pyalma.debug import setup_paramiko diff --git a/pyalma/kerberos.py b/pyalma/kerberos.py new file mode 100644 index 0000000..cb3855d --- /dev/null +++ b/pyalma/kerberos.py @@ -0,0 +1,28 @@ +import logging +from .ssh import SshClient + +class KerberosClient(SshClient): + """ + This client enforces kerberos authentication only (no password or ssh key allowed) + + Parameters: + server (str): The hostname or IP address of the SSH server. + Defaults to "alma.icr.ac.uk". + username (str): The username to use for SSH login. + sftp (str): The remote path or hostname for SFTP access. + Defaults to "alma-app.icr.ac.uk". + port (int): SSH port number. Defaults to 22. + + Usage: + client = KerberosClient(username="your_username") + # Connects automatically on initialization using key-based auth. + """ + def __init__(self, server="alma.icr.ac.uk", username=None, sftp="alma-app.icr.ac.uk", port=22, gss_auth=True): + logging.info(" Kerberos-based login activated.") + super().__init__(server=server, username=username, password=None, sftp=sftp, port=port, gss_auth=gss_auth) + + def __del__(self): + """ + Destructor that closes SSH and SFTP connections and cleans up resources. + """ + super().__del__() diff --git a/pyalma/securessh.py b/pyalma/securessh.py index 8ed5ef0..00bfc9f 100644 --- a/pyalma/securessh.py +++ b/pyalma/securessh.py @@ -30,7 +30,7 @@ class SecureSshClient(SshClient): """ def __init__(self, server="alma.icr.ac.uk", username=None, sftp="alma-app.icr.ac.uk", port=22): logging.info("🔐 Secure mode: only key-based login allowed.") - super().__init__(server=server, username=username, password=None, sftp=sftp, port=port) + super().__init__(server=server, username=username, password=None, sftp=sftp, port=port, gss_auth=False) def __del__(self): """ diff --git a/pyalma/ssh.py b/pyalma/ssh.py index 942ad39..db8efb3 100644 --- a/pyalma/ssh.py +++ b/pyalma/ssh.py @@ -15,7 +15,7 @@ class SshClient(FileReader): Enables reading, writing, listing, and transferring files on a remote server securely. """ - def __init__(self, server="alma.icr.ac.uk", username=None, password=None, sftp="alma-app.icr.ac.uk", port=22): + def __init__(self, server="alma.icr.ac.uk", username=None, password=None, sftp="alma-app.icr.ac.uk", port=22, gss_auth=False): """ Initialize SSH and SFTP connection parameters. @@ -37,7 +37,11 @@ def __init__(self, server="alma.icr.ac.uk", username=None, password=None, sftp=" self.port = port self.filter_file = os.path.join(os.path.dirname(__file__), "config", "messages.yaml") self.filtered_patterns = self._load_filtered_patterns() - self._connect(password=self.password) + self.gss_auth = gss_auth #required for kerberos authentication + self.gss_kex = False + if gss_auth: #not sure if required + self.gss_kex=True + self._connect(password=self.password,gss_auth=self.gss_auth, gss_kex=self.gss_kex) def _create_ssh_client(self): client = paramiko.SSHClient() diff --git a/requirements.txt b/requirements.txt index db36bfc..65d6c1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ PyMuPDF>=1.25.3 setuptools_scm coverage pyyaml -Pillow>=10.0.0 \ No newline at end of file +Pillow>=10.0.0 +paramiko[gssapi]>=1.9.0 \ No newline at end of file