# All standard Python modules are available for authentication service
# plug-ins to use.

import subprocess, os, sys
import traceback, re
from auth import AuthException


class OSAuth_sshException(AuthException):
    def __init__(self, msg=''):
        
        msg += '\n\n' + ''.join(traceback.format_tb(sys.exc_info()[2]))
        AuthException.__init__(self, 'ssh Authentication Error: %s' %msg)

class Auth_ssh_nix(object):
    # The "Type" of all authenticators configured from this plug-in.
    name = "ssh Login"

    # The file containing the HTML display fragment for the GUI
    # "Authentication Services" page.
    conf = "auth_ssh_nix.html"

    # The path to the binary compiled from gtauth_ssh.cpp
    install_gtauth_ssh_path = os.path.join('path', 'to', 'gtauth_ssh')

    # A tuple containing all input field names from the HTML display fragment.
    _conf_attrs = ('ssh_target_name')
    
    @classmethod
    def validate(cls, conf_data):
        # Because of satellite hubs the authenticator may
        # not run on the same platform as the administrator
        # interface. Save checking for ssh until later
        # No good way to reliably check whether a provided
        # host name is valid. Things like ping could be
        # blocked on the local system
        cdata = {}
        attr_name = cls._conf_attrs[0]
        if attr_name in conf_data:
            cdata[attr_name] = conf_data[attr_name]
        else:
            cdata[attr_name] = 'localhost'
        
        return cdata
    
    @classmethod
    def get_user(cls, username, password, conf_data):
        # Authenticate the user name/password given
        # Because of satellite hubs it is possible for the
        # authenticator to be run on a different platform
        # from where it was created.
        # Check that it can work. It will not work on
        # systems that aren't posix compatable
        if re.search('posix', os.name) == None:
            raise AuthException('Hub not running on a posix compatible system')
        # It will not work if ssh isn't available
        # Check if ssh is available
        res = subprocess.call( [ 'ssh', '-V' ] )
        if res != 0:
            raise AuthException('Unable to use ssh on system')
        # Return of 0 means successful authentication
        # pass login information in the environment for the call
        import gtr
        
        proc = subprocess.Popen([ this.install_gtauth_ssh_path ], 
                               env={'GT_USER_NAME': username,
                                    'GT_PASSWORD': password,
                                    'GT_LOGIN_DEST': conf_data[cls._conf_attrs[0]]
                                    }
                               )
        # This waits for the process to complete
        streamdata = proc.communicate()[0]
        res = proc.returncode
        if res != 0:
            if res == 1:
                # Login information not all available
                # Treat as invalid information
                return None
            elif res == 2:
                # Login credentials invalid
                return None
            elif res == 3:
                # The host is not recognized
                # ssh is asking for someone to confirm authenticity
                raise OSAuth_sshException('The authenticity of host %s cannot be verified',
                                          conf_data[cls._conf_attrs[0]])
            elif res == 4:
                raise OSAuth_sshException('pty creation failed')
            elif res == 5:
                raise OSAuth_sshException('Parent side pty setup failed')
            elif res == 6:
                raise OSAuth_sshException('Child side pty setup failed')
            elif res == 7:
                raise OSAuth_sshException('Child exec process failed')
            elif res == 8:
                raise OSAuth_sshException('Creation of child failed')
            elif res == 9:
                raise OSAuth_sshException('Password write failed')
            elif res == 10:
                raise OSAuth_sshException('Read from pty failed')
            elif res == 11:
                raise OSAuth_sshException('Login credentials no successfully passed through environment')
            else:
                raise OSAuth_sshException('Unknown error in authorization')
        
        return { 'user': username, 'email': None }
    
            
    def get_conf_html(self, conf_data=None):
        # Check sibling of this file for conf .html file.
        user_conf_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), self.conf)

        # Get default conf file to fall back on.
        import gtr
        install_conf_path = os.path.join(gtr.gthome(), 'codesonar', 'py', 'hub', 'auth', self.conf)

        conf_path = user_conf_path if os.path.exists(user_conf_path) else install_conf_path
        c = None
        with open(conf_path) as conf_file:
            c = conf_file.read()
        return c


if re.search('posix', os.name) == None:
    AUTH_PLUGINS = ()
else:
    AUTH_PLUGINS = (Auth_ssh_nix(),)

