def report(self, request, client_id):
        """Reports a log and delete the channel if relevant"""
        # logging the report
        log = []
        header_log = request.headers.get('X-KeyExchange-Log')
        if header_log is not None:
            log.append(header_log)

        body_log = request.body[:2000].strip()
        if body_log != '':
            log.append(body_log)

        # logging only if the log is not empty
        if len(log) > 0:
            log = '\n'.join(log)
            log_cef('Report', 5, request.environ, self.config, msg=log)

        # removing the channel if present
        channel_id = request.headers.get('X-KeyExchange-Cid')
        if client_id is not None and channel_id is not None:
            content = self.cache.get(channel_id)
            if content is not None:
                # the channel is still existing
                ttl, ids, data, etag = content

                # if the client_ids is in ids, we allow the deletion
                # of the channel
                if not self._delete_channel(channel_id):
                    log_cef('Could not delete the channel', 5,
                            request.environ, self.config,
                            msg=_cid2str(channel_id))
        return json_response('', 
                headers=copy.deepcopy(self.CORS_HEADERS))
    def __call__(self, request):
        if request.method == 'OPTIONS':
            sys.stderr.write("###OPTIONS: \n");
            for h in self.CORS_HEADERS:
                sys.stderr.write("   %s: %s\n" % h);
            # Trace to see if this is actually setting the headers...
            return json_response('',
                headerlist = copy.deepcopy(self.CORS_HEADERS));
        request.config = self.config
        client_id = request.headers.get('X-KeyExchange-Id')
        method = request.method
        url = request.path_info

        # the root does a health check on memcached, then
        # redirects to services.mozilla.com
        if url == '/':
            if method != 'GET':
                raise HTTPMethodNotAllowed()
            self._health_check()
            raise HTTPMovedPermanently(location=self.root)

        match = _URL.match(url)
        if match is None:
            raise HTTPNotFound()

        url = match.group(1)
        if url == 'new_channel':
            # creation of a channel
            if method != 'GET':
                raise HTTPMethodNotAllowed()
            if not self._valid_client_id(client_id):
                # The X-KeyExchange-Id is valid
                try:
                    log = 'Invalid X-KeyExchange-Id'
                    log_cef(log, 5, request.environ, self.config,
                            msg=_cid2str(client_id))
                finally:
                    raise HTTPBadRequest()
            cid = self._get_new_cid(client_id)
            headers = [('X-KeyExchange-Channel', cid),
                       ('Content-Type', 'application/json')]
            headers.extend(self.CORS_HEADERS)
            return json_response(cid, headerlist=headers)

        elif url == 'report':
            if method != 'POST':
                raise HTTPMethodNotAllowed()
            return self.report(request, client_id)

        # validating the client id - or registering id #2
        channel_content = self._check_client_id(url, client_id, request)

        # actions are dispatched in this class
        sys.stderr.write('calling ' + method + "\n");
        method = getattr(self, '%s_channel' % method.lower(), None)
        if method is None:
            sys.stderr.write("not found\n");
            raise HTTPNotFound()

        return method(request, url, channel_content)
Beispiel #3
0
def fetch_rsa_pub_key(header, **kw):
    ## if 'test' defined, use that value for the returned pub key (blech)
    if kw.get('test'):
        return kw.get('test')
    ## extract the target machine from the header.
    if kw.get('keytype', None) is None and kw.get('keyname') is None:
        raise JWSException('Must specify either keytype or keyname')
    try:
        if 'pem' in header and header.get('pem', None):
            key = base64.urlsafe_b64decode(header.get('pem')).strip()
            bio = BIO.MemoryBuffer(key)
            pubbits = RSA.load_key_bio(bio).pub()
            pub = {
                'n': int(pubbits[0].encode('hex'), 16),
                'e': int(pubbits[1].encode('hex'), 16)
            }
        elif 'jku' in header and header.get('jku', None):
            key = header['jku']
            if key.lower().startswith('data:'):
                pub = json.loads(key[key.index('base64,')+7:])
        return pub
        ""
        pub = {
            'n': key.get('modulus', None),
            'e': key.get('exponent', None)
        }
        ""
    except (AttributeError, KeyError), ex:
        cef.log_cef("Internal RSA error: %s" % str(ex),
                    5,
                    environ = kw.get('environ', None),
                    config = kw.get('config', None))
        raise(JWSException("Could not extract key"))
Beispiel #4
0
    def _check_client_id(self, channel_id, client_id, request):
        """Registers the client id into the channel.

        If there are already two registered ids, the channel is closed
        and we send back a 400. Also returns the new channel content.
        """
        if not self._valid_client_id(client_id):
            # the key is invalid
            try:
                log = 'Invalid X-KeyExchange-Id'
                log_cef(log, 5, request.environ, self.config,
                        msg=_cid2str(client_id))
            finally:
                # we need to kill the channel
                if not self._delete_channel(channel_id):
                    log_cef('Could not delete the channel', 5,
                            request.environ, self.config,
                            msg=_cid2str(channel_id))

                raise HTTPBadRequest()

        content = self.cache.get(channel_id)
        if content is None:
            # we have a valid channel id but it does not exists.
            log = 'Invalid X-KeyExchange-Channel'
            log_cef(log, 5, request.environ, self.config,
                    _cid2str(channel_id))
            raise HTTPNotFound()

        ttl, ids, data, etag = content
        if len(ids) < 2:
            # first or second id, if not already registered
            if client_id in ids:
                return content   # already registered
            ids.append(client_id)
        else:
            # already full, so either the id is present, either it's a 3rd one
            if client_id in ids:
                return  content  # already registered

            # that's an unknown id, hu-ho
            try:
                log = 'Unknown X-KeyExchange-Id'
                log_cef(log, 5, request.environ, self.config,
                        msg=_cid2str(client_id))
            finally:
                if not self._delete_channel(channel_id):
                    log_cef('Could not delete the channel', 5,
                            request.environ, self.config,
                            msg=_cid2str(channel_id))

                raise HTTPBadRequest()

        content = ttl, ids, data, etag

        # looking good
        if not self.cache.set(channel_id, content, time=ttl):
            raise HTTPServiceUnavailable()

        return content
Beispiel #5
0
    def get_channel(self, request, channel_id, existing_content):
        """Grabs data from channel if available."""
        ttl, ids, data, etag = existing_content

        # check the If-None-Match header
        if request.if_none_match is not None:
            if self._etag_match(etag, request.if_none_match):
                raise HTTPNotModified()

        # keep the GET counter up-to-date
        # the counter is a separate key
        deletion = False
        ckey = 'GET:%s' % channel_id
        count = self.cache.get(ckey)
        if count is None:
            self.cache.set(ckey, '1')
        else:
            if int(count) + 1 == self.max_gets:
                # we reached the last authorized call, the channel is remove
                # after that
                deletion = True
            else:
                self.cache.incr(ckey)

        try:
            return json_response(data, dump=False, etag=etag)
        finally:
            # deleting the channel in case we did all GETs
            if deletion:
                if not self._delete_channel(channel_id):
                    log_cef('Could not delete the channel', 5,
                            request.environ, self.config,
                            msg=_cid2str(channel_id))
Beispiel #6
0
    def decode_mac_id(self, request, tokenid):
        """Decode a MACAuth token id into its userid and MAC secret key.

        This method determines the appropriate secrets to use for the given
        request, then passes them on to tokenlib to handle the given MAC id
        token.

        If the id is invalid then ValueError will be raised.
        """
        # There might be multiple secrets in use, if we're in the
        # process of transitioning from one to another.  Try each
        # until we find one that works.
        secrets = self._get_token_secrets(request)
        for secret in secrets:
            try:
                data = tokenlib.parse_token(tokenid, secret=secret)
                userid = data["uid"]
                key = tokenlib.get_token_secret(tokenid, secret=secret)
                break
            except (ValueError, KeyError):
                pass
        else:
            log_cef("Authentication Failed: invalid MAC id", 5,
                    request.environ, request.registry.settings,
                    "", signature=AUTH_FAILURE)
            raise ValueError("invalid MAC id")
        return userid, key
Beispiel #7
0
    def decode_mac_id(self, request, tokenid):
        """Decode a MACAuth token id into its userid and MAC secret key.

        This method determines the appropriate secrets to use for the given
        request, then passes them on to tokenlib to handle the given MAC id
        token.

        If the id is invalid then ValueError will be raised.
        """
        # There might be multiple secrets in use, if we're in the
        # process of transitioning from one to another.  Try each
        # until we find one that works.
        secrets = self._get_token_secrets(request)
        for secret in secrets:
            try:
                data = tokenlib.parse_token(tokenid, secret=secret)
                userid = data["uid"]
                key = tokenlib.get_token_secret(tokenid, secret=secret)
                break
            except (ValueError, KeyError):
                pass
        else:
            log_cef("Authentication Failed: invalid MAC id",
                    5,
                    request.environ,
                    request.registry.settings,
                    "",
                    signature=AUTH_FAILURE)
            raise ValueError("invalid MAC id")
        return userid, key
Beispiel #8
0
def delete_account(request, **args):
    """Deletes a user's account and attempts to purge their sync data

    It tries the user sync node and doesn't worry overly if the delete
    request fails, as the sync data will eventually be cleaned by other
    methods
    """

    if not check_crumb(request):
        request.errors.append(_('We were unable to process your request. '
                                'Please try again.'))
        return delete_account_form(request)

    data = {'trail': [[None, _('Delete Account')]]}
    auth = request.registry["auth"]
    pwd = request.params['password']
    username = request.session.get('username')

    data['crumb'] = generate_crumb(request)
    if not auth.authenticate_user(request.user, pwd):
        request.errors.append(
                _('We were unable to authenticate your account.'))
        return delete_account_form(request)

    #if this supports a sync cluster, need to purge from there
    if "sync" in request.registry.settings.get('console.modules'):
        sync_config = \
                request.registry.settings.get('config').get_map('sync')
        auth.get_user_info(request.user, ['syncNode'])
        if request.user.get('syncNode'):
            client = SyncClient(sync_config,
                                request.user.get('syncNode'),
                                request.user.get('username'),
                                pwd)
            if not client.delete_data():
                data['alert'] = \
                  _("We were unable to delete your data on the weave node."
                    " Don't worry, it's encrypted on the node and will be"
                    " cleaned up shortly.")

    if not auth.delete_user(request.user, pwd):
        request.errors.append(_('Deleting your account failed unexpectedly. '
                          'Please try again later.'))
        return delete_account_form(request)

    log_cef('Account Deleted', 7,
            request.environ, request.registry.settings, username,
            signature='DeleteUser')
    data['username'] = None
    data['email'] = None
    data['success'] = 1
    username = None

    request.session.delete()
    return data
Beispiel #9
0
    def _log(self, name, severity, *args, **kw):
        log_cef(name, severity, self.environ, self.config, *args, **kw)

        if os.path.exists(self.filename):
            with open(self.filename) as f:
                content = f.read()

            os.remove(self.filename)
        else:
            content = ''

        return content
    def change_password(self, request):
        """Changes the user's password

        Takes a classical authentication or a reset code
        """
        # the body is in plain text utf8 string
        new_password = request.body.decode('utf8')

        if not valid_password(request.user.get('username'), new_password):
            raise HTTPBadRequest('Password should be at least 8 '
                                 'characters and not the same as your '
                                 'username')

        key = request.headers.get('X-Weave-Password-Reset')

        if key is not None:
            user_id = self.auth.get_user_id(request.user)

            if user_id is None:
                raise HTTPNotFound()

            if not self.reset.verify_reset_code(request.user, key):
                log_cef('Invalid Reset Code submitted',
                        5,
                        request.environ,
                        self.app.config,
                        request.user['username'],
                        'InvalidResetCode',
                        submitedtoken=key)

                raise HTTPJsonBadRequest(ERROR_INVALID_RESET_CODE)

            if not self.auth.admin_update_password(request.user, new_password,
                                                   key):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')
        else:
            # classical auth
            self.app.auth.authenticate_user(request, self.app.config,
                                            request.user['username'])

            if request.user['userid'] is None:
                log_cef('User Authentication Failed', 5, request.environ,
                        self.app.config, request.user['username'],
                        AUTH_FAILURE)
                raise HTTPUnauthorized()

            if not self.auth.update_password(
                    request.user, request.user_password, new_password):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')

        return text_response('success')
Beispiel #11
0
    def _log(self, name, severity, *args, **kw):
        log_cef(name, severity, self.environ, self.config, *args, **kw)

        if os.path.exists(self.filename):
            with open(self.filename) as f:
                content = f.read()

            os.remove(self.filename)
        else:
            content = ''

        return content
Beispiel #12
0
    def delete_password_reset(self, request, **data):
        """Forces a password reset clear"""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        self._check_captcha(request, data)
        self.auth.get_user_id(request.user)
        self.reset.clear_reset_code(request.user)
        log_cef("User requested password reset clear", 9, request.environ,
                self.app.config, request.user.get('username'),
                PASSWD_RESET_CLR)
        return text_response('success')
    def delete_password_reset(self, request, **data):
        """Forces a password reset clear"""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        self._check_captcha(request, data)
        self.auth.get_user_id(request.user)
        self.reset.clear_reset_code(request.user)
        log_cef("User requested password reset clear",
                9, request.environ, self.app.config,
                request.user.get('username'), PASSWD_RESET_CLR)
        return text_response('success')
Beispiel #14
0
def cef_event(name, severity, **custom_exts):
    # Extra values need to be in the format csNLabel=xxx, csN=yyy
    extra_exts = {}
    n = 2
    for k, v in custom_exts.iteritems():
        valueKey = 'cs%d' % n
        labelKey = '%sLabel' % valueKey
        extra_exts[labelKey] = k
        extra_exts[valueKey] = v
        n += 1

    username = request.environ.get('REMOTE_USER', 'Unknown User')
    cef.log_cef(name, severity, request.environ, cef_config, username=username, **extra_exts)
    def decode_hawk_id(self, request, tokenid):
        """Decode a Hawk token id into its userid and secret key.

        This method determines the appropriate secrets to use for the given
        request, then passes them on to tokenlib to handle the given Hawk
        token.  If the id is invalid then ValueError will be raised.

        Unlike the superclass method, this implementation allows expired
        tokens to be used up to a configurable timeout.  The effective userid
        for expired tokens is changed to be "expired:<uid>".
        """
        now = time.time()
        node_name = self._get_node_name(request)
        # There might be multiple secrets in use,
        # so try each until we find one that works.
        secrets = self._get_token_secrets(node_name)
        for secret in secrets:
            try:
                tm = tokenlib.TokenManager(secret=secret)
                # Check for a proper valid signature first.
                # If that failed because of an expired token, check if
                # it falls within the allowable expired-token window.
                try:
                    data = tm.parse_token(tokenid, now=now)
                except tokenlib.errors.ExpiredTokenError:
                    recently = now - self.expired_token_timeout
                    data = tm.parse_token(tokenid, now=recently)
                    data["uid"] = "expired:%d" % (data["uid"], )
            except ValueError:
                # Token validation failed, move on to the next secret.
                continue
            else:
                # Token validation succeeded, quit the loop.
                break
        else:
            # The token failed to validate using any secret.
            log_cef("Authentication Failed: invalid hawk id",
                    5,
                    request.environ,
                    request.registry.settings,
                    "",
                    signature=AUTH_FAILURE)
            raise ValueError("invalid Hawk id")
        # Sanity-check the contained data.
        # Any errors raise ValueError, triggering auth failure.
        try:
            userid = data["uid"]
            token_node_name = data["node"]
        except KeyError, e:
            msg = "missing value in token data: %s"
            raise ValueError(msg % (e, ))
Beispiel #16
0
    def __call__(self, request):
        request.config = self.config
        client_id = request.headers.get('X-KeyExchange-Id')
        method = request.method
        url = request.path_info

        # the root does a health check on memcached, then
        # redirects to services.mozilla.com
        if url == '/':
            if method != 'GET':
                raise HTTPMethodNotAllowed()
            self._health_check()
            raise HTTPMovedPermanently(location=self.root)

        match = _URL.match(url)
        if match is None:
            raise HTTPNotFound()

        url = match.group(1)
        if url == 'new_channel':
            # creation of a channel
            if method != 'GET':
                raise HTTPMethodNotAllowed()
            if not self._valid_client_id(client_id):
                # The X-KeyExchange-Id is valid
                try:
                    log = 'Invalid X-KeyExchange-Id'
                    log_cef(log, 5, request.environ, self.config,
                            msg=_cid2str(client_id))
                finally:
                    raise HTTPBadRequest()
            cid = self._get_new_cid(client_id)
            headers = [('X-KeyExchange-Channel', cid),
                       ('Content-Type', 'application/json')]
            return json_response(cid, headerlist=headers)

        elif url == 'report':
            if method != 'POST':
                raise HTTPMethodNotAllowed()
            return self.report(request, client_id)

        # validating the client id - or registering id #2
        channel_content = self._check_client_id(url, client_id, request)

        # actions are dispatched in this class
        method = getattr(self, '%s_channel' % method.lower(), None)
        if method is None:
            raise HTTPNotFound()

        return method(request, url, channel_content)
Beispiel #17
0
 def sign(self, payload, header = None, alg = None, **kw):
     if payload is None:
         raise (JWSException("Cannot encode empty payload"))
     header = self.header(alg = alg)
     if alg is None:
         alg = header.get('alg', 'NONE')
     try:
         signer = self._sign.get(alg[:2].upper())
     except KeyError, ex:
         cef.log_cef("Invalid JWS Sign method specified %s", str(ex),
                     5,
                     self.environ,
                     self._config)
         raise(JWSException("Unsupported encoding method specified"))
Beispiel #18
0
def report(signal, message=None, flag=None, sender=None, values=None,
           request_path=None, request_meta=None, **kwargs):
    g = functools.partial(getattr, settings)
    severity = g('CEF_DEFAULT_SEVERITY', 5)
    cef_kw = {'msg': message, 'signature': request_path,
            'config': {
                'cef.product': g('CEF_PRODUCT', 'paranoia'),
                'cef.vendor': g('CEF_VENDOR', 'Mozilla'),
                'cef.version': g('CEF_VERSION', '0'),
                'cef.device_version': g('CEF_DEVICE_VERSION', '0'),
                'cef.file': g('CEF_FILE', 'syslog'),
            }
        }
    log_cef(message, severity, request_meta, **cef_kw)
Beispiel #19
0
def authenticate(request, credentials, attrs=()):
    """Authenticate a dict of credentials against the configured user backend.

    This is a handy callback that you can use to check a dict of credentials
    against the configured auth backend.  It will accept credentials from any
    of the auth schemes supported by the backend.  If the authentication is
    successful it will update request.user with the user object loaded from
    the backend.
    """
    # Use whatever auth backend has been configured.
    auth = request.registry.get("auth")
    if auth is None:
        return False

    # Update an existing user object if one exists on the request.
    user = getattr(request, "user", None)
    if user is None:
        user = {}

    # Ensure that we have credentials["username"] for use by the backend.
    # Some repoze.who plugins like to use "login" instead of "username".
    if "username" not in credentials:
        if "login" in credentials:
            credentials["username"] = credentials.pop("login")
        else:
            log_cef("Authentication attemped without username", 5,
                    request.environ, request.registry.settings,
                    "", signature=AUTH_FAILURE)
            return False

    # Normalize the password, if any, to be unicode.
    password = credentials.get("password")
    if password is not None and not isinstance(password, unicode):
        try:
            credentials["password"] = password.decode("utf8")
        except UnicodeDecodeError:
            return None

    # Authenticate against the configured backend.
    if not auth.authenticate_user(user, credentials, attrs):
        log_cef("Authentication Failed", 5,
                request.environ, request.registry.settings,
                credentials["username"],
                signature=AUTH_FAILURE)
        return False

    # Store the user dict on the request, and return it for conveience.
    if getattr(request, "user", None) is None:
        request.user = user
    return user
Beispiel #20
0
    def change_password(self, request):
        """Changes the user's password

        Takes a classical authentication or a reset code
        """
        # the body is in plain text utf8 string
        new_password = request.body.decode('utf8')

        if not valid_password(request.user.get('username'), new_password):
            raise HTTPBadRequest('Password should be at least 8 '
                                 'characters and not the same as your '
                                 'username')

        key = request.headers.get('X-Weave-Password-Reset')

        if key is not None:
            user_id = self.auth.get_user_id(request.user)

            if user_id is None:
                raise HTTPNotFound()

            if not self.reset.verify_reset_code(request.user, key):
                log_cef('Invalid Reset Code submitted', 5, request.environ,
                        self.app.config, request.user['username'],
                        'InvalidResetCode', submitedtoken=key)

                raise HTTPJsonBadRequest(ERROR_INVALID_RESET_CODE)

            if not self.auth.admin_update_password(request.user,
                                                   new_password, key):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')
        else:
            # classical auth
            self.app.auth.authenticate_user(request, self.app.config,
                                            request.user['username'])

            if request.user['userid'] is None:
                log_cef('User Authentication Failed', 5, request.environ,
                        self.app.config, request.user['username'],
                        AUTH_FAILURE)
                raise HTTPUnauthorized()

            if not self.auth.update_password(request.user,
                                             request.user_password,
                                             new_password):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')

        return text_response('success')
    def decode_hawk_id(self, request, tokenid):
        """Decode a Hawk token id into its userid and secret key.

        This method determines the appropriate secrets to use for the given
        request, then passes them on to tokenlib to handle the given Hawk
        token.  If the id is invalid then ValueError will be raised.

        Unlike the superclass method, this implementation allows expired
        tokens to be used up to a configurable timeout.  The effective userid
        for expired tokens is changed to be "expired:<uid>".
        """
        now = time.time()
        node_name = self._get_node_name(request)
        # There might be multiple secrets in use,
        # so try each until we find one that works.
        secrets = self._get_token_secrets(node_name)
        for secret in secrets:
            try:
                tm = tokenlib.TokenManager(secret=secret)
                # Check for a proper valid signature first.
                # If that failed because of an expired token, check if
                # it falls within the allowable expired-token window.
                try:
                    data = tm.parse_token(tokenid, now=now)
                except tokenlib.errors.ExpiredTokenError:
                    recently = now - self.expired_token_timeout
                    data = tm.parse_token(tokenid, now=recently)
                    data["uid"] = "expired:%d" % (data["uid"],)
            except ValueError:
                # Token validation failed, move on to the next secret.
                continue
            else:
                # Token validation succeeded, quit the loop.
                break
        else:
            # The token failed to validate using any secret.
            log_cef("Authentication Failed: invalid hawk id", 5,
                    request.environ, request.registry.settings,
                    "", signature=AUTH_FAILURE)
            raise ValueError("invalid Hawk id")
        # Sanity-check the contained data.
        # Any errors raise ValueError, triggering auth failure.
        try:
            userid = data["uid"]
            token_node_name = data["node"]
        except KeyError, e:
            msg = "missing value in token data: %s"
            raise ValueError(msg % (e,))
Beispiel #22
0
def report(signal, message=None, flag=None, sender=None, values=None,
           request_path=None, request_meta=None, **kwargs):
    g = functools.partial(getattr, settings)
    severity = g('CEF_DEFAULT_SEVERITY', 5)
    cef_kw = {
        'msg': message,
        'signature': request_path,
        'config': {
            'cef.product': g('CEF_PRODUCT', 'paranoia'),
            'cef.vendor': g('CEF_VENDOR', 'Mozilla'),
            'cef.version': g('CEF_VERSION', '0'),
            'cef.device_version': g('CEF_DEVICE_VERSION', '0'),
            'cef.file': g('CEF_FILE', 'syslog'),
        }
    }
    log_cef(message, severity, request_meta, **cef_kw)
Beispiel #23
0
    def test_formater_unicode(self):
        config = {'cef.version': '0', 'cef.vendor': 'mozilla',
                  'cef.device_version': '3', 'cef.product': 'weave',
                  'cef': True, 'cef.file': mkstemp()[1]}
        file_ = config['cef.file']

        environ = {'PATH_INFO':
                u'/reviewers/receipt/issue/\u043f\u0442\u0442-news'}
        kw = {'cs2': 1L,
              'cs2Label': u'\xd0'}

        log_cef('name', 0, environ, config, username=u'tarek', **kw)
        with open(file_) as f:
            data = f.read()

        self.assertTrue('cs2Label=\xc3\x90' in data, data)
Beispiel #24
0
    def test_formater_unicode(self):
        config = {'cef.version': '0', 'cef.vendor': 'mozilla',
                  'cef.device_version': '3', 'cef.product': 'weave',
                  'cef': True, 'cef.file': mkstemp()[1]}
        file_ = config['cef.file']

        environ = {'PATH_INFO':
                   u'/reviewers/receipt/issue/\u043f\u0442\u0442-news'}
        kw = {'cs2': 1L,
              'cs2Label': u'\xd0'}

        log_cef('name', 0, environ, config, username=u'tarek', **kw)
        with open(file_) as f:
            data = f.read()

        self.assertTrue('cs2Label=\xc3\x90' in data, data)
Beispiel #25
0
    def _check_signature(self, request, key):
        """Check the MACAuth signature on the request.

        This method checks the MAC signature on the request against the
        supplied signing key.  If missing or invalid then HTTPUnauthorized
        is raised.

        The SagradaAuthenticationPolicy implementation wraps the default
        MACAuthenticationPolicy implementation with some cef logging.
        """
        supercls = super(SagradaAuthenticationPolicy, self)
        try:
            return supercls._check_signature(request, key)
        except HTTPUnauthorized:
            log_cef("Authentication Failed: invalid MAC signature", 5,
                    request.environ, request.registry.settings,
                    "", signature=AUTH_FAILURE)
            raise
def cef_event(name, severity, **custom_exts):
    # Extra values need to be in the format csNLabel=xxx, csN=yyy
    extra_exts = {}
    n = 2
    for k, v in custom_exts.iteritems():
        valueKey = 'cs%d' % n
        labelKey = '%sLabel' % valueKey
        extra_exts[labelKey] = k
        extra_exts[valueKey] = v
        n += 1

    username = request.environ.get('REMOTE_USER', 'Unknown User')
    cef.log_cef(name,
                severity,
                request.environ,
                kickoff.app.config,
                username=username,
                **extra_exts)
Beispiel #27
0
def forgot_step_4(request, **args):
    """Final step. reset their password, clear their reset code, and let
    them know that we're done.
    """
    data = {}
    username = extract_username(request.params.get('key_username'))
    request.user['username'] = username

    #verify that password and confirm match
    password = request.params.get('new_password')
    confirm = request.params.get('confirm_password')
    if password != confirm:
        request.errors.append(_('The new password and confirmation do '
                                'not match. Please try again.'))
        return render_to_response('console/password_reset3.mako',
                                  forgot_step_3(request), request)

    if not valid_password(username, password):
        request.errors.append(_('The new password is not valid. '
                                'Please try again.'))
        return render_to_response('console/password_reset3.mako',
                                  forgot_step_3(request), request)

    try:
        auth = request.registry["auth"]
        reset = request.registry.settings.get('app.console.reset')
        if not auth.admin_update_password(request.user,
                                             password, request.params['key']):
            request.errors.append(_('Changing the password failed. '
                         'Please ask for a new key and try again later'))
            return data
    except InvalidCodeError:
            request.errors.append(_('The reset code you submitted was '
                              'invalid. Please request a new one.'))
            return render_to_response('console/password_reset2.mako',
                                      forgot_step_1(request), request)

    log_cef('Password Changed', 5,
            request.environ,
            request.registry.settings.get('config').get_map(),
            username, signature="PasswordReset")
    reset.clear_reset_code(request.user)
    return data
Beispiel #28
0
def change_password(request, **args):
    """Processes the change-password form"""

    if not check_crumb(request):
        request.errors.append(_('We were unable to process your request. '
                                'Please try again.'))
        return change_password_form(request)

    auth = request.registry["auth"]
    data = {'trail': [[None, _('Change Password')]]}

    password = request.params['new_password']

    #generate them a new crumb in case there's a problem
    data['crumb'] = generate_crumb(request)

    confirm = request.params.get('confirm')
    if password != confirm:
        request.errors.append(_('The new password and confirmation do not '
                                'match. Please try again.'))
        return change_password_form(request)

    username = request.session['username']
    if not valid_password(username, password):
        request.errors.append(_('Please make sure your password is at '
                                'least 8 characters long.'))
        return change_password_form(request)

    if not auth.update_password(request.user, request.session.get('password'),
                                password):
        request.errors.append(
            _('An unknown problem ocurred. Please try again later.'))
        return change_password_form(request)

    data['success'] = _('Your password was succesfully changed.')
    request.session['password'] = password
    log_cef('Password Changed', 5,
            request.environ, request.registry.settings,
            username, signature='PasswordReset')

    return data
Beispiel #29
0
    def _check_signature(self, request, key):
        """Check the MACAuth signature on the request.

        This method checks the MAC signature on the request against the
        supplied signing key.  If missing or invalid then HTTPUnauthorized
        is raised.

        The SagradaAuthenticationPolicy implementation wraps the default
        MACAuthenticationPolicy implementation with some cef logging.
        """
        supercls = super(SagradaAuthenticationPolicy, self)
        try:
            return supercls._check_signature(request, key)
        except HTTPUnauthorized:
            log_cef("Authentication Failed: invalid MAC signature",
                    5,
                    request.environ,
                    request.registry.settings,
                    "",
                    signature=AUTH_FAILURE)
            raise
 def log_cef(self, name, severity, *args, **kwargs):
     cef_settings = self.application.__dict__.get('cef_settings')
     if cef_settings:
         c = {'cef.product': cef_settings.get("product"),
              'cef.vendor': cef_settings.get("vendor"),
              'cef.version': cef_settings.get("version"),
              'cef.device_version': cef_settings.get("device_version"),
              'cef.file': cef_settings.get("file")}
         env = { 'REQUEST_METHOD': self.request.method,
                 'PATH_INFO': self.request.uri,
                 'HTTP_HOST': self.request.host,
                 'HTTP_USER_AGENT': self.request.headers.get('User-Agent', '') }
         return cef.log_cef(name, severity, env, *args, config=c, **kwargs)
Beispiel #31
0
    def verify(self, jwso):
        import pdb; pdb.set_trace();
        # TODO: Do verification
        return True

        if not jwso:
            raise (JWSException("Cannot verify empty JWS"))
        try:
            import pdb; pdb.set_trace()
            if alg is None:
                alg = jwso['assertion']['head'].get('alg', 'NONE')
            try:
                sigcheck = self._verify.get(alg[:2].upper())
            except KeyError, ex:
                cef.log_cef("Invalid JWS Sign method specified %s", str(ex),
                            5,
                            self.environ,
                            self._config)
                raise(JWSException("Unsupported encoding method specified"))
            return sigcheck(alg,
                            jwso['header'],
                            '%s.%s' % (header_str, payload_str),
                            signature)
Beispiel #32
0
    def authenticate(self, environ, identity):
        # Normalize the username for our backend.
        # Some repoze.who plugins use "login" instead of "username".
        username = identity.get("username")
        if username is None:
            username = identity.get("login")
            if username is None:
                return None
        orig_username = username
        identity["username"] = username = extract_username(username)

        # Normalize the password, if any, to be unicode.
        if "password" in identity:
            try:
                identity["password"] = identity["password"].decode("utf8")
            except UnicodeDecodeError:
                return None

        # Decide whether it's a new-style or old-style auth backend.
        if hasattr(self.backend, 'generate_reset_code'):
            user = self._authenticate_oldstyle(environ, username, identity)
        else:
            user = self._authenticate_newstyle(environ, username, identity)

        # Log the error if that failed.
        if user is None:
            err_username = username
            if username != orig_username:
                err_username += ' (%s)' % (orig_username,)
            log_cef('User Authentication Failed', 5, environ, self.config,
                    err_username, AUTH_FAILURE)
            return None

        # Success!  Store any loaded attributes into the identity dict.
        identity.update(user)
        return user["username"]
Beispiel #33
0
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        if 'REMOTE_USER' in environ:
            # already authenticated
            return environ['REMOTE_USER']

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                user_name, password = base64.decodestring(auth).split(':')
            except (binascii.Error, ValueError):
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                log_cef('Username Does Not Match URL', 7, environ, config)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                log_cef('Invalid characters specified in username ', 5,
                            environ, config)
                raise HTTPBadRequest('Invalid characters specified in ' +
                                     'username', {}, 'Username must be BIDI ' +
                                     'compliant UTF-8')

            # let's try an authentication
            user_id = self.backend.authenticate_user(user_name, password)
            if user_id is None:
                err = 'Authentication Failed for Backend service ' + user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                        err += ' (%s)' % (remote_user_original)
                log_cef(err, 5, environ, config)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']
            del environ['HTTP_AUTHORIZATION']
            return user_id
Beispiel #34
0
def forgot_step_2(request, **args):
    """Tries to send the email with a reset code, then lets the user know
    we've done that
    """
    data = {}
    auth = request.registry["auth"]
    username = extract_username(request.params['username'])
    request.user['username'] = username

    user_id = auth.get_user_id(request.user)
    if not user_id:
        request.errors.append(_('Unable to locate your account. '
                                'Please check your username.'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    if not request.registry.settings['app.captcha'].check(request):
        log_cef('Captcha failed on forgot password', 3,
                request.environ,
                request.registry.settings.get('config').get_map(),
                username, signature=CAPTCHA_FAILURE)
        request.errors.append(_('The captcha did not match. '
                                'Please try again'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    try:
        reset = request.registry.settings.get('app.console.reset')
        reset_code = reset.generate_reset_code(request.user, True)
        if not reset_code:
            request.errors.append(_('Getting a reset code failed '
                              'unexpectedly. Please try again later.'))
            logger.error("Could not generate a reset code")
            return render_to_response('console/password_reset1.mako',
                                      forgot_step_1(request), request)
        auth.get_user_info(request.user, ['mail'])
        if not valid_email(request.user['mail']):
            raise NoEmailError()

        maildata = {'forgot_url': '%s/forgot' % request.host_url,
                    'username': username,
                    'code': reset_code}
        template_path = get_template_lookup('console')
        template = \
            template_path.get_template('password_reset_mail.mako')
        body = template.render(**maildata)
        subject = _('Resetting your Mozilla Services password')
        smtp = request.registry.settings.get('config').get_map('smtp')
        #sender has a required position, so we can't pass it in in the
        #dict
        sender = smtp['sender']
        del smtp['sender']
        send_email(sender, request.user['mail'],
                   subject, body, **smtp)

    except AlreadySentError:
        #backend handled the reset code email. Keep going
        pass
    except NoEmailError:
        request.errors.append(_('We do not have an email on file for this '
                          'account and cannot send you a reset code.'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    return data
Beispiel #35
0
def ac_ajax_server(request):
    if request.is_ajax():
        print "at ac_ajax_server"
        tamperBoo = False

        usrInput = request.POST

        # Get the user from user id
        try: # Ensure the input is an integer
            inpUserId = int( usrInput['inpNameId'] )

            # check that the UserId is valid
            # step_0. get the user's id from server side
            serversUser = MembersPostUser.objects.get(user = request.user.username)
            serversUserId = int( serversUser.id )
            # step_1. If user is super, ID must be within the range of ids
            addUser = ""
            if request.user.has_perm('msw.superuser_display'):
                try: # Ensure the integer is valid
                    addUser = MembersPostUser.objects.get(id = inpUserId)
                except:
                    # TODO: Add CEF log say invalid integer range
                    tamperBoo = True
            # step_2. If user is not super, ID must match its userid
            else:
                if serversUserId == inpUserId:
                    addUser = MembersPostUser.objects.get(id = inpUserId)
                else:
                    tamperBoo = True
        except:
            # TODO: Add CEF log say invalid non-integer input
            tamperBoo = True

        # Get the Text, since the 2 tables are linked, must get text object!
        try: # Ensure the input is an integer
            inpTextId = int( usrInput['inpTextId'] )

            try: # Ensure the integer is valid
                addText = MembersPostText.objects.get(id = inpTextId)
            except:
                # TODO: Add CEF log say invalid integer range
                tamperBoo = True

            # put new entry into database
            if not tamperBoo:
                MembersPostSay.objects.create(mpuser=addUser, mptext=addText)
        except:
            # TODO: Add CEF log say invalid non-integer input
            tamperBoo = True
        
        # publish it
        file = 'msw/demos/children/ac_ajax_table.html'
        if tamperBoo:
            ctx = {
                "tamper_msg": "Please stop tampering"
            }
        else:
            # from vendor-local/packages/cef/test_cef.py
            environ = {'REMOTE_ADDR': '127.0.0.1', 'HTTP_HOST': '127.0.0.1',
                        'PATH_INFO': '/', 'REQUEST_METHOD': 'GET',
                        'HTTP_USER_AGENT': 'MySuperBrowser'}

            #config = {'cef.version': '0', 'cef.vendor': 'mozilla',
            #           'cef.device_version': '3', 'cef.product': 'weave',
            #           'cef.file': 'syslog',
            #           'cef': True}
            config = {'cef.version': '0', 'cef.vendor': 'mozilla',
                       'cef.device_version': '3', 'cef.product': 'weave',
                       'cef.file': 'syslog', 
                       'cef.syslog.priority' : 'ERR',
                       'cef.syslog.facility' : 'AUTH',
                       'cef.syslog.options' : 'PID,CONS',
                       'cef': True}
            log_cef("Hello world!", 2, environ, config, msg="Welcome to a new day!")
            ''' Yay in my /var/log/secure.log I have
            Jul 19 11:48:57 host-3-248 manage.py[3889]: Jul 19 11:48:57 host-3-248.mv.mozilla.com CEF:0|moz     illa|weave|3|Hello world!|Hello world!|2|cs1Label=requestClientApplication cs1=MySuperBrowser r     equestMethod=GET request=/ src=127.0.0.1 dest=127.0.0.1 suser=none msg=Welcome to a new day!
            '''
            ctx = {
                "all_postsay_list": MembersPostSay.objects.all().order_by('-id')[:5]
            }
        response = jingo.render(request, file, ctx)
        return response

        # Attempting JSON
        #print "&&&&&&&&&&&&&&&&&&&"
        #import pdb; pdb.set_trace()
        #jsontexts = json.dumps(texts)
        #print "*****************************" 
        #print jsontexts
        #return HttpResponse( jsontexts)

    else:
        # TODO: return a 404 or 405. (from cvan comment in 2343852088f41d521263819d12692bcabff3ebf6)
        warning = "WARNING: SQL AJAX FAILED"        
        print warning
        return HttpResponse(warning)
Beispiel #36
0
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        if 'REMOTE_USER' in environ:
            # already authenticated
            return environ['REMOTE_USER']

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                # Split in such a way as to preserve
                # passwords that contain ':'.
                user_name, password = base64.decodestring(auth).split(':', 1)
            except (binascii.Error, ValueError):
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                log_cef('Username Does Not Match URL', 7, environ, config,
                        user_name, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                raise HTTPBadRequest('Invalid characters specified in ' +
                                     'username', {}, 'Username must be BIDI ' +
                                     'compliant UTF-8')

            # let's try an authentication
            # the authenticate_user API takes a unicode UTF-8 for the password
            try:
                password = password.decode('utf8')
            except UnicodeDecodeError:
                raise HTTPUnauthorized()

            #first we need to figure out if this is old-style or new-style auth
            if hasattr(self.backend, 'generate_reset_code'):

            # XXX to be removed once we get the proper fix see bug #662859
                if (hasattr(self.backend, 'check_node')
                    and self.backend.check_node):
                    user_id = self.backend.authenticate_user(user_name,
                                            password, environ.get('HTTP_HOST'))
                else:
                    user_id = self.backend.authenticate_user(user_name,
                                                             password)
                request.user = User(user_name, user_id)
            else:
                user = User(user_name)
                credentials = {"username": user_name, "password": password}
                user_id = self.backend.authenticate_user(user, credentials,
                                                         ['syncNode'])
                if not user_id:
                    user_id = None
                    user = None
                else:
                    if (self.config.get('auth.check_node')
                        and user.get('syncNode') != environ.get('HTTP_HOST')):
                        user_id = None
                        user = None

                request.user = user

            if user_id is None:
                err_user = user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                        err_user += ' (%s)' % (remote_user_original)
                log_cef('User Authentication Failed', 5, environ, config,
                        err_user, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']

            del environ['HTTP_AUTHORIZATION']
            return user_id
Beispiel #37
0
 def blacklisted(self, ip, environ):
     log_cef('BlackListed IP', 5, environ, self.config, msg=ip)
Beispiel #38
0
def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=
        ('Submit TruSTAR reports from a CSV file\n'
         'Example:\n\n'
         'python ingest_csv.py -c "TargetIP,SourceIP,Info,Analysis,Indicators" -t "TrackingNumber" -d "ReportTime" -cn "CaseName" -f reportname.csv'
         ))
    parser.add_argument('-f',
                        '--file',
                        required=True,
                        dest='file_name',
                        help='csv file to import')
    parser.add_argument('-t',
                        '--title',
                        required=True,
                        dest='title_col',
                        help='Name of column to use as title field')
    parser.add_argument('-d',
                        '--datetime',
                        required=False,
                        dest='datetime_col',
                        help='Name of column to use as report date/time')
    parser.add_argument('-c',
                        '--columns',
                        required=False,
                        dest='cols',
                        help='List of comma-separated column names to include')
    parser.add_argument(
        '-n',
        '--num-reports',
        required=False,
        dest='num_reports',
        type=int,
        default=1000,
        help='Max number of reports to submit (top-down order)')
    parser.add_argument(
        '-o',
        '--output',
        required=False,
        dest='cef_output_file',
        default='trustar.cef',
        help=
        'Common Event Format (CEF) output log file, one event is generated per successful submission'
    )
    parser.add_argument(
        '-ci',
        '--case-id',
        required=False,
        dest='caseid_col',
        help='Name of column to use as report case ID for CEF export')
    args = parser.parse_args()

    allowed_keys_content = []

    if args.cols:
        allowed_keys_content = args.cols.split(",")

    ts = TruStar(config_role="trustar")
    token = ts.get_token()

    df = pd.read_csv(args.file_name, nrows=args.num_reports, encoding="latin1")

    # Create title and report content from the provided column names (if any)
    all_reports = []

    for report_num in range(0, len(df)):
        current_content = ''
        current_title = ''
        current_datetime = None
        current_case_id = 0
        current_report = {}

        for key in df:
            # ignore empty cells, which are float64 NaNs
            cell_value = df[key][report_num]

            if pd.isnull(cell_value):
                continue

            cell_value = "%s" % cell_value

            # encode any unicode chars
            string_value = cell_value.encode('utf-8').strip()
            if string_value == "nan":
                print("%s -> %s" % (key, string_value))
                continue

            content = "{}:\n {}\n \n".format(key, string_value)

            if not allowed_keys_content or key in allowed_keys_content:
                current_content += content
            if key == args.title_col:
                current_title = str(df[key][report_num])
            if key == args.datetime_col:
                current_datetime = str(df[key][report_num])
            if key == args.caseid_col:
                current_case_id = str(df[key][report_num])

        current_report['reportTitle'] = current_title
        current_report['reportDateTime'] = current_datetime
        current_report['reportContent'] = current_content
        current_report['reportCaseId'] = current_case_id

        all_reports.append(current_report)

    if do_enclave_submissions:
        num_submitted = 0
        for staged_report in all_reports:

            successful = False
            attempts = 0
            while not successful and attempts < 5:
                attempts += 1
                try:
                    response = ts.submit_report(
                        token,
                        report_body_txt=staged_report['reportContent'],
                        report_name=staged_report['reportTitle'],
                        began_time=staged_report['reportDateTime'],
                        enclave=True)
                    if 'error' in response:
                        print("Submission failed with error: %s, %s" %
                              (response['error'], response['message']))
                        if response['error'] in ("Internal Server Error",
                                                 "Access token expired",
                                                 "Authentication error"):
                            print("Auth token expired, requesting new one")
                            token = ts.get_token()
                        else:
                            raise Exception
                    else:
                        num_submitted += 1
                        successful = True

                        print(
                            "Submitted report #%s-%s title %s as TruSTAR IR %s with case ID: %s"
                            % (num_submitted, attempts,
                               staged_report['reportTitle'],
                               response['reportId'],
                               staged_report['reportCaseId']))

                        print("URL: %s" %
                              ts.get_report_url(response['reportId']))

                        # Build CEF output:
                        # - HTTP_USER_AGENT is the cs1 field
                        # - example CEF output: CEF:version|vendor|product|device_version|signature|name|severity|cs1=(num_submitted) cs2=(report_url)
                        config = {
                            'cef.version': '0.5',
                            'cef.vendor': 'TruSTAR',
                            'cef.device_version': '2.0',
                            'cef.product': 'API',
                            'cef': True,
                            'cef.file': args.cef_output_file
                        }

                        environ = {
                            'REMOTE_ADDR': '127.0.0.1',
                            'HTTP_HOST': '127.0.0.1',
                            'HTTP_USER_AGENT': staged_report['reportTitle']
                        }

                        log_cef('SUBMISSION',
                                1,
                                environ,
                                config,
                                signature="INFO",
                                cs2=staged_report['reportCaseId'],
                                cs3=ts.get_report_url(response['reportId']))

                        ####
                        # TODO: ADD YOUR CUSTOM POST-PROCESSING CODE FOR THIS SUBMISSION HERE
                        ####

                        if 'reportIndicators' in response and len(
                                response['reportIndicators']) > 0:
                            print("Indicators:\n %s" %
                                  (json.dumps(response['reportIndicators'])))
                        print()

                except Exception as e:
                    traceback.print_exc(file=sys.stdout)
                    print("Problem submitting report: %s" % e)
                    time.sleep(5)

            # Sleep between submissions
            time.sleep(5)
Beispiel #39
0
                alg = jwso['assertion']['head'].get('alg', 'NONE')
            try:
                sigcheck = self._verify.get(alg[:2].upper())
            except KeyError, ex:
                cef.log_cef("Invalid JWS Sign method specified %s", str(ex),
                            5,
                            self.environ,
                            self._config)
                raise(JWSException("Unsupported encoding method specified"))
            return sigcheck(alg,
                            jwso['header'],
                            '%s.%s' % (header_str, payload_str),
                            signature)
        except ValueError, ex:
            cef.log_cef("JWS Verification error: %s" % ex,
                        5,
                        self.environ,
                        self._config)
            raise(JWSException("JWS has invalid format"))

    def _sign_NONE(self, alg, header, sbs):
        """ No encryption has no encryption.
            duh.
        """
        return None;

    def _get_sha(self, depth):
        depths = {'256': sha256,
                 '384': sha384,
                 '512': sha512}
        if depth not in depths:
            raise(JWSException('Invalid Depth specified for HS'))
Beispiel #40
0
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        if 'REMOTE_USER' in environ:
            # already authenticated
            return environ['REMOTE_USER']

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                user_name, password = base64.decodestring(auth).split(':')
            except (binascii.Error, ValueError):
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                log_cef('Username Does Not Match URL', 7, environ, config)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                log_cef('Invalid characters specified in username ', 5,
                        environ, config)
                raise HTTPBadRequest(
                    'Invalid characters specified in ' + 'username', {},
                    'Username must be BIDI ' + 'compliant UTF-8')

            # let's try an authentication
            user_id = self.backend.authenticate_user(user_name, password)
            if user_id is None:
                err = 'Authentication Failed for Backend service ' + user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                    err += ' (%s)' % (remote_user_original)
                log_cef(err, 5, environ, config)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']
            del environ['HTTP_AUTHORIZATION']
            return user_id