Esempio n. 1
0
    def _do_login(self, user, password, load_index=False, redirect=False):
        session, config = self.session, self.session.config
        session_id = self.session.ui.html_variables.get('http_session')

        # This prevents folks from sending us a DEFAULT user (upper case),
        # which is an internal security bypass below.
        user = user and user.lower()

        if not user:
            from mailpile.config import SecurePassphraseStorage
            sps = SecurePassphraseStorage(password)
            password = ''
            try:
                # Verify the passphrase
                gpg = GnuPG(use_agent=False)
                if gpg.is_available():
                    gpg.passphrase = sps.get_reader()
                    assert(gpg.sign('Sign This!')[0] == 0)

                    # Store the varified passphrase
                    config.gnupg_passphrase.data = sps.data

                    # Load the config and index, if necessary
                    if not config.loaded_config:
                        self._config()
                        if load_index:
                            self._idx()
                        else:
                            pass  # FIXME: Start load in background

                    session.ui.debug('Good passphrase for %s' % session_id)
                    return self._logged_in(redirect=redirect)
                else:
                    session.ui.debug('No GnuPG, checking DEFAULT user')
                    # No GnuPG, see if there is a DEFAULT user in the config
                    user = '******'

            except (AssertionError, IOError):
                session.ui.debug('Bad passphrase for %s' % session_id)
                return self._error(_('Invalid passphrase, please try again'))

        if user in config.logins or user == 'DEFAULT':
            # FIXME: Salt and hash the password, check if it matches
            #        the entry in our user/password list (TODO).
            # NOTE:  This hack effectively disables auth without GnUPG
            if user == 'DEFAULT':
                session.ui.debug('FIXME: Unauthorized login allowed')
                return self._logged_in(redirect=redirect)
            raise Exception('FIXME')

        self._error(_('Incorrect username or password'))
Esempio n. 2
0
File: auth.py Progetto: dkm/Mailpile
def VerifyAndStorePassphrase(config, passphrase=None, sps=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert(sps is not None)
    gpg = GnuPG(use_agent=False)
    if gpg.is_available():
        gpg.passphrase = sps.get_reader()
        gpgr = config.prefs.gpg_recipient
        gpgr = gpgr if (gpgr not in (None, '', '!CREATE')) else None
        assert(gpg.sign('Sign This!', fromkey=gpgr)[0] == 0)

    return sps
Esempio n. 3
0
def VerifyAndStorePassphrase(config, passphrase=None, sps=None, key=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert (sps is not None)
    gpg = GnuPG(use_agent=False)
    if gpg.is_available():
        gpg.passphrase = sps.get_reader()
        gpgr = config.prefs.gpg_recipient
        gpgr = key or (gpgr if (gpgr not in (None, '', '!CREATE')) else None)
        assert (gpg.sign('Sign This!', fromkey=gpgr)[0] == 0)

    return sps
Esempio n. 4
0
def VerifyAndStorePassphrase(config, passphrase=None, sps=None, key=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert (sps is not None)
    gpg = GnuPG(None, use_agent=False)
    if gpg.is_available():
        gpg.passphrase = sps.get_reader()
        gpgr = config.prefs.gpg_recipient
        gpgr = key or (gpgr if (gpgr not in (None, '', '!CREATE')) else None)
        assert (gpg.sign('Sign This!', fromkey=gpgr)[0] == 0)

    # Fun side effect: changing the passphrase invalidates the message cache
    import mailpile.mailutils
    mailpile.mailutils.ClearParseCache(full=True)

    return sps
Esempio n. 5
0
def VerifyAndStorePassphrase(config, passphrase=None, sps=None,
                                     key=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert(sps is not None)
    gpg = GnuPG(None, use_agent=False)
    if gpg.is_available():
        gpg.passphrase = sps.get_reader()
        gpgr = config.prefs.gpg_recipient
        gpgr = key or (gpgr if (gpgr not in (None, '', '!CREATE')) else None)
        assert(gpg.sign('Sign This!', fromkey=gpgr)[0] == 0)

    # Fun side effect: changing the passphrase invalidates the message cache
    import mailpile.mailutils
    mailpile.mailutils.ClearParseCache(full=True)

    return sps
Esempio n. 6
0
def VerifyAndStorePassphrase(config, passphrase=None, sps=None, key=None):
    if passphrase and not sps:
        from mailpile.config import SecurePassphraseStorage
        sps = SecurePassphraseStorage(passphrase)
        passphrase = 'this probably does not really overwrite :-( '

    assert (sps is not None)
    assert (config.load_master_key(sps))

    # Fun side effect: changing the passphrase invalidates the message cache
    import mailpile.mailutils
    mailpile.mailutils.ClearParseCache(full=True)

    return sps
Esempio n. 7
0
    def setup_command(self, session):
        changed = False
        if self.data.get('_method') == 'POST' or self._testing():
            name, email, note, pwd = (self.data.get(k, [None])[0]
                                      for k in ('name', 'email', 'note',
                                                'pass'))
            if email:
                rv = AddProfile(session, data=self.data).run()
                if rv.status == 'success':
                    #
                    # FIXME: We need to fire off a background process to
                    #        try and auto-discover routes and sources.
                    #
                    if not session.config.prefs.default_email:
                        session.config.prefs.default_email = email
                        changed = True
                    self.save_profiles_to_key()
                else:
                    return self._error(_('Failed to add profile'),
                                       info=rv.error_info,
                                       result=self._result())
            if email and pwd:
                sps = SecurePassphraseStorage(pwd)
                SetupProfiles.PASSWORD_CACHE[email] = sps

            result = self._result()
            if not result['default_email']:
                profiles = result['profiles'].values()
                profiles.sort(
                    key=lambda p: (len(p['pgp_keys']), len(p['name'])))
                e = result['default_email'] = profiles[-1]['email']
                session.config.prefs.default_email = e
                changed = True
        else:
            result = self._result()

        if changed:
            self._background_save(config=True)

        return self._success(_('Your profiles'), result)
Esempio n. 8
0
    def command(self):
        config = self.session.config

        policyttl = self.args[1] if (len(self.args) > 1) else 'cache-only:-1'
        if 'policy-ttl' in self.data:
            policyttl = self.data['policy-ttl'][0]
        if ':' in policyttl:
            policy, ttl = policyttl.split(':')
        else:
            policy, ttl = policyttl, -1
        if 'policy' in self.data:
            policy = self.data['policy'][0]
        if 'ttl' in self.data:
            ttl = self.data['policy'][0]


        fingerprint = info = None
        keyid = self.args[0] if self.args else self.data.get('id', [None])[0]
        if keyid:
            fingerprint, info = self._lookup_key(keyid)
            result = {'key': info}
        else:
            result = {'keylist': self._gnupg().list_secret_keys()}

        if self.data.get('_method', None) == 'GET':
            password = False
            return self._success(_('Enter your password'), result)

        assert(keyid is not None and fingerprint is not None)
        def happy(msg):
            # Fun side effect: changing the passphrase invalidates the message cache
            import mailpile.mailutils
            mailpile.mailutils.ClearParseCache(full=True)

            redirect = self.data.get('redirect', [None])[0]
            if redirect:
                raise UrlRedirectException(redirect)
            return self._success(msg, result)

        if policy == 'forget':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            if fingerprint in config.secrets:
                config.secrets[fingerprint].password = ''
            return happy(_('Password forgotten!'))

        if policy == 'fail':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {
                'policy': policy
            }
            return happy(_('Password will never be stored'))

        if self.data.get('_method', None) == 'POST':
            password = self.data.get('password', [None])[0]
        else:
            password = self.session.ui.get_password(_('Enter your password:'******' ')

        if policy == 'store':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {
                'password': password,
                'policy': policy
            }
            return happy(_('Password stored permanently'))

        elif policy == 'cache-only' and password:
            from mailpile.config import SecurePassphraseStorage
            sps = SecurePassphraseStorage(password)
            sps.expiration = time.time() + float(ttl)
            config.passphrases[fingerprint] = sps
            if fingerprint.lower() in config.secrets:
                del config.secrets[fingerprint.lower()]
            return happy(_('Password stored temporarily'))

        else:
            return self._error(_('Invalid password policy!'), result)
Esempio n. 9
0
    def command(self):
        config = self.session.config

        policyttl = self.args[1] if (len(self.args) > 1) else 'cache-only:-1'
        if 'policy-ttl' in self.data:
            policyttl = self.data['policy-ttl'][0]
        if ':' in policyttl:
            policy, ttl = policyttl.split(':')
        else:
            policy, ttl = policyttl, -1
        if 'policy' in self.data:
            policy = self.data['policy'][0]
        if 'ttl' in self.data:
            ttl = self.data['policy'][0]

        fingerprint = info = None
        keyid = self.args[0] if self.args else self.data.get('id', [None])[0]
        if keyid:
            fingerprint, info = self._lookup_key(keyid)
            result = {'key': info}
        else:
            result = {'keylist': self._gnupg().list_secret_keys()}

        if self.data.get('_method', None) == 'GET':
            password = False
            return self._success(_('Enter your password'), result)

        assert (keyid is not None and fingerprint is not None)

        def happy(msg):
            # Fun side effect: changing the passphrase invalidates the message cache
            import mailpile.mailutils
            mailpile.mailutils.ClearParseCache(full=True)

            redirect = self.data.get('redirect', [None])[0]
            if redirect:
                raise UrlRedirectException(redirect)
            return self._success(msg, result)

        if policy == 'forget':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            if fingerprint in config.secrets:
                config.secrets[fingerprint].password = ''
            return happy(_('Password forgotten!'))

        if policy == 'fail':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {'policy': policy}
            return happy(_('Password will never be stored'))

        if self.data.get('_method', None) == 'POST':
            password = self.data.get('password', [None])[0]
        else:
            password = self.session.ui.get_password(
                _('Enter your password:'******' ')

        if policy == 'store':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {
                'password': password,
                'policy': policy
            }
            return happy(_('Password stored permanently'))

        elif policy == 'cache-only' and password:
            from mailpile.config import SecurePassphraseStorage
            sps = SecurePassphraseStorage(password)
            sps.expiration = time.time() + float(ttl)
            config.passphrases[fingerprint] = sps
            if fingerprint.lower() in config.secrets:
                del config.secrets[fingerprint.lower()]
            return happy(_('Password stored temporarily'))

        else:
            return self._error(_('Invalid password policy!'), result)
Esempio n. 10
0
    def setup_command(self, session):
        changed = authed = False
        results = {
            'secret_keys': self.list_secret_keys(),
        }
        error_info = None

        if self.data.get('_method') == 'POST' or self._testing():

            # 1st, are we choosing or creating a new key?
            choose_key = self.data.get('choose_key', [''])[0]
            if choose_key and not error_info:
                if (choose_key not in results['secret_keys'] and
                        choose_key != '!CREATE'):
                    error_info = (_('Invalid key'), {
                        'invalid_key': True,
                        'chosen_key': choose_key
                    })

            # 2nd, check authentication...
            #
            # FIXME: Creating a new key will allow a malicious actor to
            #        bypass authentication and change settings.
            #
            try:
                passphrase = self.data.get('passphrase', [''])[0]
                passphrase2 = self.data.get('passphrase_confirm', [''])[0]
                chosen_key = ((not error_info) and choose_key
                              ) or session.config.prefs.gpg_recipient

                if not error_info:
                    assert(passphrase == passphrase2)
                    if chosen_key == '!CREATE':
                        assert(passphrase != '')
                        sps = SecurePassphraseStorage(passphrase)
                    elif chosen_key:
                        sps = mailpile.auth.VerifyAndStorePassphrase(
                            session.config,
                            passphrase=passphrase,
                            key=chosen_key)
                    else:
                        sps = mailpile.auth.VerifyAndStorePassphrase(
                            session.config, passphrase=passphrase)
                    if not chosen_key:
                        choose_key = '!CREATE'
                    results['updated_passphrase'] = True
                    session.config.gnupg_passphrase.data = sps.data
                    mailpile.auth.SetLoggedIn(self)
            except AssertionError:
                error_info = (_('Invalid passphrase'), {
                    'invalid_passphrase': True,
                    'chosen_key': session.config.prefs.gpg_recipient
                })

            # 3rd, if necessary master key and/or GPG key
            with BLOCK_HTTPD_LOCK, Idle_HTTPD():
                if choose_key and not error_info:
                    session.config.prefs.gpg_recipient = choose_key
                    # FIXME: This should probably only happen if the GPG
                    #        key was successfully created.
                    self.make_master_key()
                    changed = True

                with Setup.KEY_WORKER_LOCK:
                    if ((not error_info) and
                            (session.config.prefs.gpg_recipient
                             == '!CREATE') and
                            (Setup.KEY_CREATING_THREAD is None or
                             Setup.KEY_CREATING_THREAD.failed)):
                        gk = GnuPGKeyGenerator(
                            sps=session.config.gnupg_passphrase,
                            on_complete=('notify',
                                         lambda: self.gpg_key_ready(gk)))
                        Setup.KEY_CREATING_THREAD = gk
                        Setup.KEY_CREATING_THREAD.start()

            # Finally we update misc. settings
            for key in self.HTTP_POST_VARS.keys():
                # FIXME: This should probably only happen if the GPG
                #        key was successfully created.

                # Continue iff all is well...
                if error_info:
                    break
                if key in (['choose_key', 'passphrase', 'passphrase_confirm'] +
                           TestableWebbable.HTTP_POST_VARS.keys()):
                    continue
                try:
                    val = self.data.get(key, [''])[0]
                    if val:
                        session.config.prefs[key] = self.TRUTHY[val.lower()]
                        changed = True
                except (ValueError, KeyError):
                    error_info = (_('Invalid preference'), {
                        'invalid_setting': True,
                        'variable': key
                    })

        results.update({
            'creating_key': (Setup.KEY_CREATING_THREAD is not None and
                             Setup.KEY_CREATING_THREAD.running),
            'creating_failed': (Setup.KEY_CREATING_THREAD is not None and
                                Setup.KEY_CREATING_THREAD.failed),
            'chosen_key': session.config.prefs.gpg_recipient,
            'prefs': {
                'index_encrypted': session.config.prefs.index_encrypted,
                'obfuscate_index': session.config.prefs.obfuscate_index,
                'encrypt_mail': session.config.prefs.encrypt_mail,
                'encrypt_index': session.config.prefs.encrypt_index,
                'encrypt_vcards': session.config.prefs.encrypt_vcards,
                'encrypt_events': session.config.prefs.encrypt_events,
                'encrypt_misc': session.config.prefs.encrypt_misc
            }
        })

        if changed:
            self._background_save(config=True)

        if error_info:
            return self._error(error_info[0],
                               info=error_info[1], result=results)
        elif changed:
            return self._success(_('Updated crypto preferences'), results)
        else:
            return self._success(_('Configure crypto preferences'), results)