Example #1
0
    def run(self):
        ''' Main authenticator controller loop.
        '''
        while True:
            try:
                ifaces = getInterfaces()
                if __DEBUG__:
                    logDebug(
                        'Checking available wireless interfaces: {0}'.format(
                            str(ifaces)))
                # We don't need to do anything if there is no wireless interface available.
                if ifaces == []:
                    raise _WaitForNextEvent()

                # Do we already have internet access?
                if __DEBUG__:
                    logDebug(
                        'About to ping {0} in order to check for internet access.'
                        .format(quote(self.__configDaemon.pingSite)))
                redirectURL = hlm_http.detectRedirect(
                    self.__configDaemon.pingSite)
                if redirectURL == None:
                    # Update status
                    self.status['connected'] = True
                    if not self.status['wasOurJob']:
                        self.status['message'] = _(
                            'Connected to the internet (not thanks to HLM though).'
                        )

                    if __DEBUG__:
                        logDebug(
                            'Ping URL {0} was not redirected. We have internet access.'
                            .format(quote(self.__configDaemon.pingSite)))
                    raise _WaitForNextEvent()

                # We don't know yet if we actually need to authenticate (it could be a standard website redirection)
                self.status['connected'] = None
                self.status['wasOurJob'] = False
                self.status['message'] = _(
                    'A redirection was detected, you may be behind a captive portal. Trying to authenticate...'
                )

                if __DEBUG__:
                    logDebug(
                        'Ping URL {0} was redirected to {1}. Trying to find a plugin that accepts the redirected URL...'
                        .format(quote(self.__configDaemon.pingSite),
                                quote(redirectURL)))

                # Get currently configured SSIDs so the plugins can rely on it too
                connectedSSIDs = [getSSID(iface) for iface in ifaces]
                if __DEBUG__:
                    logDebug('Available SSIDs: {0}'.format(connectedSSIDs))

                # Try each relevant authentication plugin in turn
                for plugin in self.__relevantPlugins:
                    # Verify the redirected URL
                    isSupported = False
                    supportedRedirects = plugin.getSupportedRedirectPrefixes()
                    for redirectPrefix in supportedRedirects:
                        if redirectURL.startswith(redirectPrefix):
                            isSupported = True
                            break
                    if not isSupported:
                        continue
                    # Verify the connected SSIDs
                    isSupported = False
                    supportedSSIDs = plugin.supportedSSIDs
                    for ssid in connectedSSIDs:
                        if ssid in supportedSSIDs:
                            isSupported = True
                            break
                    if not isSupported:
                        continue
                    # The plugin matches both the redirectURL and the connected SSIDs, let's try to authenticate!
                    if __DEBUG__:
                        logDebug(
                            'AuthPlugin {0} could match, trying to authenticate...'
                            .format(quote(plugin.pluginName)))

                    try:
                        plugin.authenticate(redirectURL, connectedSSIDs)

                    except SystemExit:
                        raise

                    except hlm_auth_plugins.Status_Success as exc:
                        self.status['connected'] = True
                        self.status['wasOurJob'] = True
                        self.status['message'] = exc.message
                        self.dispatcher.notify('[ok] ' + exc.message)
                        if __INFO__: logInfo(exc.message)
                        raise _WaitForNextEvent()

                    except hlm_auth_plugins.Status_WrongCredentials as exc:
                        self.status['message'] = exc.message
                        self.dispatcher.notify('[warning] ' + exc.message)
                        if __WARNING__: logWarning(exc.message)

                    except hlm_auth_plugins.Status_Error as exc:
                        if __DEBUG__: logDebug(exc.message)

                    except hlm_http.CertificateError as exc:
                        exc_message = _(
                            'The hotspot\'s SSL certificate is invalid!\nNo credentials were sent, it may be a phishing hotspot.'
                        )
                        self.dispatcher.notify('[error] ' + exc_message)
                        logError(exc_message + ' ' + str(exc))

                    except BaseException as exc:
                        raise Exception(
                            'AuthPlugin {0}: [UNEXPECTED FAILURE] {1}'.format(
                                quote(plugin.pluginName), exc))

                self.status['connected'] = None
                self.status['wasOurJob'] = False
                self.status['message'] = _(
                    'Unknown connection status (a redirect was detected, but no authentication plugin managed to log you in).'
                )

            except _WaitForNextEvent:
                pass
            except SystemExit:
                pass
            except BaseException as exc:
                if __DEBUG__: logDebug('Authenticator.run(): {0}'.format(exc))

            # Wait for the next event
            if __DEBUG__:
                logDebug('Going to sleep for {0} seconds.'.format(
                    hlm_config.antiDosPingInterval))
            time.sleep(hlm_config.antiDosPingInterval)
            if __DEBUG__: logDebug('Waiting for the next event.')
            self.__antiDosWaiting = False
            self.wakeUp.wait(self.__sleepInterval)
            self.wakeUp.clear()
            self.__antiDosWaiting = True
            if __DEBUG__: logDebug('Authenticator thread woke up.')
Example #2
0
def authenticate(redirectURL, connectedSSIDs):

    debugMessageHeader = 'AuthPlugin {0}'.format(quote(pluginName))
    def debugMessage(message, *args):
        if args != tuple():
            message = message.format(*args)
        message = '{0}: {1}'.format(debugMessageHeader, message)
        return message


    def reportFailure(message, *args):
        message = debugMessage('[FAILURE] ' + message, *args)
        raise hlm_auth_plugins.Status_Error(pluginName, message)

    match = _regexDomainRedirect.search(redirectURL)
    if match == None:
        reportFailure('hotspot domain name is missing.')
    domainRedirect = match.group(1)
    if __DEBUG__: logDebug(debugMessage('domainRedirect is {0}'.format(domainRedirect)))
    regexChilliURL = re.compile('SFRLoginURL_JIL=(https://{0}/indexEncryptingChilli.php?[^>]+)-->'.format(re.escape(domainRedirect)))

    # Extract the URL arguments
    try:
        urlArgs = hlm_http.splitUrlArguments(redirectURL, ['challenge', 'mode', 'uamip', 'uamport', 'channel'], 'redirect URL')
        if __DEBUG__: logDebug(debugMessage('got all required arguments from the redirect URL.'))
    except BaseException as exc:
        reportFailure(exc)

    # Get the login page
    try:
        result = hlm_http.urlOpener().open(redirectURL, timeout = 10)
        pageData = hlm_http.readAll(result)
        if not (type(pageData) is str):
          pageData = str(pageData, 'utf-8')
        result.close()
        if __DEBUG__: logDebug(debugMessage('grabbed the login webpage.'))
    except hlm_http.CertificateError as exc:
        raise
    except BaseException as exc:
        reportFailure('error while grabbing the login webpage: {0}'.format(exc))

    # Basic check to see if we actually are on a SFR "NeufBox"
    if _regexCheckNB4.search(pageData) == None:
        reportFailure('this is not a "NeufBox4".')
    if __DEBUG__: logDebug(debugMessage('seems we have a "NeufBox".'))

    # Is the hotspot FON-enabled?
    hasFONsupport = (_regexCheckChoiceFON.search(pageData) != None)
    if __DEBUG__:
        if hasFONsupport:
            logDebug(debugMessage('we have FON support.'))
        else:
            logDebug(debugMessage('we don\'t have FON support.'))

    # Double-check the Chillispot URL
    match = regexChilliURL.search(pageData)
    if match == None:
        reportFailure('in-page data is missing.')
    if match.group(1) != redirectURL:
        reportFailure('in-page data conflicts with the redirected URL.')
    if __DEBUG__: logDebug(debugMessage('in-page data confirms the redirect URL.'))

    # Prepare data that is dependent on the kind of hotspot / configured credentials
    if 'sfr.fr' in pluginCredentials:
        hotspotCredentials = 'sfr.fr'
        hotspotAccessType = 'neuf'
        if hasFONsupport:
            hotspotChoice = 'choix=neuf&'
        else:
            hotspotChoice = ''
    elif hasFONsupport and ('fon' in pluginCredentials):
        hotspotCredentials = 'fon'
        hotspotAccessType = 'fon'
        hotspotChoice = 'choix=fon&'
    else:
        reportFailure('this plugin only supports «sfr.fr» and «fon» credentials.')

    if __DEBUG__: logDebug(debugMessage('using {0} credentials'.format(quote(hotspotCredentials))))
    debugMessageHeader = 'AuthPlugin {0} (credentials {1})'.format(quote(pluginName), quote(hotspotCredentials))

    (user, password) = pluginCredentials[hotspotCredentials]
    postData = hotspotChoice + 'username={0}&password={1}&conditions=on&challenge={2}&accessType={7}&lang=fr&mode={3}&userurl=http%253a%252f%252fwww.google.com%252f&uamip={4}&uamport={5}&channel={6}&connexion=Connexion'.format(urllib.parse.quote(user), urllib.parse.quote(password), urlArgs['challenge'], urlArgs['mode'], urlArgs['uamip'], urlArgs['uamport'], urlArgs['channel'], hotspotAccessType)

    # Ask the hotspot gateway to give us the Chillispot URL
    try:
        # FIXME Python 3.2 (postData)
        result = hlm_http.urlOpener().open('https://{0}/nb4_crypt.php'.format(domainRedirect), data = postData, timeout = 10)
        pageData = hlm_http.readAll(result)
        if not (type(pageData) is str):
          pageData = str(pageData, 'utf-8')
        result.close()
        if __DEBUG__: logDebug(debugMessage('grabbed the encryption gateway (JS redirect) result webpage.'))
    except hlm_http.CertificateError as exc:
        raise
    except BaseException as exc:
        reportFailure('error while grabbing the encryption gateway (JS redirect) result webpage: {0}'.format(exc))

    # OK, now we have to put up with a Javascript redirect. I mean, WTF?
    match = _regexJSRedirect.search(pageData)
    if match == None:
        reportFailure('missing URL in the encryption gateway (JS redirect) result webpage.')
    redirectURL = match.group(1)
    # Let's see what Chillispot will answer us...
    redirectURL = hlm_http.detectRedirect(redirectURL)
    if redirectURL == None:
        reportFailure('something went wrong during the Chillispot query (redirect expected, but none obtained).')

    # Check the final URL arguments
    try:
        urlArgs = hlm_http.splitUrlArguments(redirectURL, ['res'], 'redirect URL')
        urlArgs = urlArgs['res'].lower()
    except BaseException as exc:
        reportFailure(exc)

    if urlArgs == 'failed':
        raise hlm_auth_plugins.Status_WrongCredentials(pluginName, hotspotCredentials)

    if (urlArgs != 'success') and (urlArgs != 'already'):
        reportFailure('Chillispot didn\'t let us log in, no idea why. Here\'s the redirected URL: {0}'.format(redirectURL))

    raise hlm_auth_plugins.Status_Success(pluginName, hotspotCredentials)
    def run(self):
        ''' Main authenticator controller loop.
        '''
        while True:
            try:
                ifaces = getInterfaces()
                if __DEBUG__: logDebug('Checking available wireless interfaces: {0}'.format(str(ifaces)))
                # We don't need to do anything if there is no wireless interface available.
                if ifaces == []:
                    raise _WaitForNextEvent()

                # Do we already have internet access?
                if __DEBUG__: logDebug('About to ping {0} in order to check for internet access.'.format(quote(self.__configDaemon.pingSite)))
                redirectURL = hlm_http.detectRedirect(self.__configDaemon.pingSite)
                if redirectURL == None:
                    # Update status
                    self.status['connected'] = True
                    if not self.status['wasOurJob']:
                        self.status['message'] = _('Connected to the internet (not thanks to HLM though).')

                    if __DEBUG__: logDebug('Ping URL {0} was not redirected. We have internet access.'.format(quote(self.__configDaemon.pingSite)))
                    raise _WaitForNextEvent()


                # We don't know yet if we actually need to authenticate (it could be a standard website redirection)
                self.status['connected'] = None
                self.status['wasOurJob'] = False
                self.status['message'] = _('A redirection was detected, you may be behind a captive portal. Trying to authenticate...')

                if __DEBUG__: logDebug('Ping URL {0} was redirected to {1}. Trying to find a plugin that accepts the redirected URL...'.format(quote(self.__configDaemon.pingSite), quote(redirectURL)))

                # Get currently configured SSIDs so the plugins can rely on it too
                connectedSSIDs = [getSSID(iface) for iface in ifaces]
                if __DEBUG__: logDebug('Available SSIDs: {0}'.format(connectedSSIDs))

                # Try each relevant authentication plugin in turn
                for plugin in self.__relevantPlugins:
                    # Verify the redirected URL
                    isSupported = False
                    supportedRedirects = plugin.getSupportedRedirectPrefixes()
                    for redirectPrefix in supportedRedirects:
                        if redirectURL.startswith(redirectPrefix):
                            isSupported = True
                            break
                    if not isSupported:
                        continue
                    # Verify the connected SSIDs
                    isSupported = False
                    supportedSSIDs = plugin.supportedSSIDs
                    for ssid in connectedSSIDs:
                        if ssid in supportedSSIDs:
                            isSupported = True
                            break
                    if not isSupported:
                        continue
                    # The plugin matches both the redirectURL and the connected SSIDs, let's try to authenticate!
                    if __DEBUG__: logDebug('AuthPlugin {0} could match, trying to authenticate...'.format(quote(plugin.pluginName)))

                    try:
                        plugin.authenticate(redirectURL, connectedSSIDs)

                    except SystemExit:
                        raise

                    except hlm_auth_plugins.Status_Success as exc:
                        self.status['connected'] = True
                        self.status['wasOurJob'] = True
                        self.status['message'] = exc.message
                        self.dispatcher.notify('[ok] ' + exc.message)
                        if __INFO__: logInfo(exc.message)
                        raise _WaitForNextEvent()

                    except hlm_auth_plugins.Status_WrongCredentials as exc:
                        self.status['message'] = exc.message
                        self.dispatcher.notify('[warning] ' + exc.message)
                        if __WARNING__: logWarning(exc.message)

                    except hlm_auth_plugins.Status_Error as exc:
                        if __DEBUG__: logDebug(exc.message)

                    except hlm_http.CertificateError as exc:
                        exc_message = _('The hotspot\'s SSL certificate is invalid!\nNo credentials were sent, it may be a phishing hotspot.')
                        self.dispatcher.notify('[error] ' + exc_message)
                        logError(exc_message + ' ' + str(exc))

                    except BaseException as exc:
                        raise Exception('AuthPlugin {0}: [UNEXPECTED FAILURE] {1}'.format(quote(plugin.pluginName), exc))

                self.status['connected'] = None
                self.status['wasOurJob'] = False
                self.status['message'] = _('Unknown connection status (a redirect was detected, but no authentication plugin managed to log you in).')

            except _WaitForNextEvent:
                pass
            except SystemExit:
                pass
            except BaseException as exc:
                if __DEBUG__: logDebug('Authenticator.run(): {0}'.format(exc))

            # Wait for the next event
            if __DEBUG__: logDebug('Going to sleep for {0} seconds.'.format(hlm_config.antiDosPingInterval))
            time.sleep(hlm_config.antiDosPingInterval)
            if __DEBUG__: logDebug('Waiting for the next event.')
            self.__antiDosWaiting = False
            self.wakeUp.wait(self.__sleepInterval)
            self.wakeUp.clear()
            self.__antiDosWaiting = True
            if __DEBUG__: logDebug('Authenticator thread woke up.')