Beispiel #1
0
 def test_hex_entropy(self):
     """hex_entropy() returns random hex digits"""
     hex_digits = set('0123456789abcdef')
     for i in xrange(129):
         entropy = util.hex_entropy(i)
         self.assertEqual(i, len(entropy))
         self.assertEqual(set(), set(entropy) - hex_digits)
Beispiel #2
0
 def test_hex_entropy(self):
     """hex_entropy() returns random hex digits"""
     hex_digits = set('0123456789abcdef')
     for i in xrange(129):
         entropy = util.hex_entropy(i)
         self.assertEqual(i, len(entropy))
         self.assertEqual(set(), set(entropy) - hex_digits)
Beispiel #3
0
    def test_file_metadata(self):
        pkgname = 'TestModule_' + util.hex_entropy(16)
        modname = pkgname.lower()
        with open(os.path.join(self.dir, pkgname + '-0.1.egg-info'), 'w') as f:
            f.write('Metadata-Version: 1.1\n'
                    'Name: %(pkgname)s\n'
                    'Version: 0.1\n'
                    'Author: Joe\n'
                    'Author-email: [email protected]\n'
                    'Home-page: http://example.org/\n'
                    'Summary: summary.\n'
                    'Description: description.\n'
                    'Provides: %(modname)s\n'
                    'Provides: %(modname)s.foo\n' % {
                        'pkgname': pkgname,
                        'modname': modname
                    })
        os.mkdir(os.path.join(self.dir, modname))
        for name in ('__init__.py', 'bar.py', 'foo.py'):
            with open(os.path.join(self.dir, modname, name), 'w') as f:
                f.write('# -*- coding: utf-8 -*-\n')

        mod = __import__(modname, {}, {}, ['bar', 'foo'])
        pkginfo = util.get_pkginfo(mod)
        self.assertEqual('0.1', pkginfo['version'])
        self.assertEqual('Joe', pkginfo['author'])
        self.assertEqual('*****@*****.**', pkginfo['author_email'])
        self.assertEqual('http://example.org/', pkginfo['home_page'])
        self.assertEqual('summary.', pkginfo['summary'])
        self.assertEqual('description.', pkginfo['description'])
        self.assertEqual(pkginfo, util.get_pkginfo(mod.bar))
        self.assertEqual(pkginfo, util.get_pkginfo(mod.foo))
Beispiel #4
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name
        is available. The user name is inserted into the `auth_cookie`
        table and a cookie identifying the user on subsequent requests
        is sent back to the client.

        If the Authenticator was created with `ignore_case` set to
        true, then the authentication name passed from the web server
        in req.remote_user will be converted to lower case before
        being used. This is to avoid problems on installations
        authenticating against Windows which is not case sensitive
        regarding user names and domain names
        """
        if not req.remote_user:
            # TRANSLATOR: ... refer to the 'installation documentation'. (link)
            inst_doc = tag.a(_("installation documentation"),
                             title=_("Configuring Authentication"),
                             href=req.href.wiki('TracInstall') +
                                                "#ConfiguringAuthentication")
            raise TracError(tag_("Authentication information not available. "
                                 "Please refer to the %(inst_doc)s.",
                                 inst_doc=inst_doc))
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        if req.authname not in ('anonymous', remote_user):
            raise TracError(_("Already logged in as %(user)s.",
                              user=req.authname))

        with self.env.db_transaction as db:
            # Delete cookies older than 10 days
            db("DELETE FROM auth_cookie WHERE time < %s",
               (int(time_now()) - 86400 * 10,))
            # Insert a new cookie if we haven't already got one
            cookie = None
            trac_auth = req.incookie.get('trac_auth')
            if trac_auth is not None:
                name = self._cookie_to_name(req, trac_auth)
                cookie = trac_auth.value if name == remote_user else None
            if cookie is None:
                cookie = hex_entropy()
                db("""
                    INSERT INTO auth_cookie (cookie, name, ipnr, time)
                         VALUES (%s, %s, %s, %s)
                   """, (cookie, remote_user, req.remote_addr,
                         int(time_now())))
        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        if self.auth_cookie_domain:
            req.outcookie['trac_auth']['domain'] = self.auth_cookie_domain
        req.outcookie['trac_auth']['path'] = self.auth_cookie_path \
                                             or req.base_path or '/'
        if self.env.secure_cookies:
            req.outcookie['trac_auth']['secure'] = True
        req.outcookie['trac_auth']['httponly'] = True
        if self.auth_cookie_lifetime > 0:
            req.outcookie['trac_auth']['expires'] = self.auth_cookie_lifetime
Beispiel #5
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name
        is available. The user name is inserted into the `auth_cookie`
        table and a cookie identifying the user on subsequent requests
        is sent back to the client.

        If the Authenticator was created with `ignore_case` set to
        true, then the authentication name passed from the web server
        in req.remote_user will be converted to lower case before
        being used. This is to avoid problems on installations
        authenticating against Windows which is not case sensitive
        regarding user names and domain names
        """
        if not req.remote_user:
            # TRANSLATOR: ... refer to the 'installation documentation'. (link)
            inst_doc = tag.a(_('installation documentation'),
                             title=_("Configuring Authentication"),
                             href=req.href.wiki('TracInstall')
                                  + "#ConfiguringAuthentication")
            raise TracError(tag_("Authentication information not available. "
                                 "Please refer to the %(inst_doc)s.",
                                 inst_doc=inst_doc))
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        if req.authname not in ('anonymous', remote_user):
            raise TracError(_('Already logged in as %(user)s.',
                              user=req.authname))

        with self.env.db_transaction as db:
            # Delete cookies older than 10 days
            db("DELETE FROM auth_cookie WHERE time < %s",
               (int(time.time()) - 86400 * 10,))
            # Insert a new cookie if we haven't already got one
            cookie = None
            trac_auth = req.incookie.get('trac_auth')
            if trac_auth is not None:
                name = self._cookie_to_name(req, trac_auth)
                cookie = trac_auth.value if name == remote_user else None
            if cookie is None:
                cookie = hex_entropy()
                db("""
                    INSERT INTO auth_cookie (cookie, name, ipnr, time)
                         VALUES (%s, %s, %s, %s)
                   """, (cookie, remote_user, req.remote_addr,
                         int(time.time())))
        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = self.auth_cookie_path \
                                             or req.base_path or '/'
        if self.env.secure_cookies:
            req.outcookie['trac_auth']['secure'] = True
        if sys.version_info >= (2, 6):
            req.outcookie['trac_auth']['httponly'] = True
        if self.auth_cookie_lifetime > 0:
            req.outcookie['trac_auth']['expires'] = self.auth_cookie_lifetime
Beispiel #6
0
    def _do_login(self, req):
        """Log the remote user in.
	
	This function displays a form to the user to log themselves in, and
	verifies the information when the user submits that form. If the
	authentication is successful, the user name is inserted into the
	`auth_cookie` table and a cookie identifying the user on subsequent
	requests is sent back to the client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web form 'username' variable
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """

        if req.args.get("username"):
            assert req.args.get("password"), "No password"
            # Test authentication

            try:
                self._try_http_auth(
                    req.base_url[: req.base_url.find("/", 8)] + "/login",
                    req.args.get("username"),
                    req.args.get("password"),
                )
            except IOError, e:
                # Incorrect password
                req.hdf["title"] = "Login Failed"
                req.hdf["login.action"] = self.env.href() + "/login"
                req.hdf["login.referer"] = req.args.get("ref")
                req.hdf["login.error"] = "Invalid username or password"
                return None

                # Successful authentication, set cookies and stuff
            remote_user = req.args.get("username")
            ignore_case = self.env.config.get("trac", "ignore_auth_case")
            ignore_case = ignore_case.strip().lower() in TRUE
            if ignore_case:
                remote_user = remote_user.lower()

            assert req.authname in ("anonymous", remote_user), "Already logged in as %s." % req.authname

            cookie = hex_entropy()
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute(
                "INSERT INTO auth_cookie (cookie,name,ipnr,time) " "VALUES (%s, %s, %s, %s)",
                (cookie, remote_user, req.remote_addr, int(time.time())),
            )
            db.commit()

            req.authname = remote_user
            req.outcookie["trac_auth"] = cookie
            req.outcookie["trac_auth"]["path"] = self.env.href()
            req.redirect(req.args.get("ref") or self.env.abs_href())
Beispiel #7
0
    def _do_login(self, req):
        """Log the remote user in.
	
	This function displays a form to the user to log themselves in, and
	verifies the information when the user submits that form. If the
	authentication is successful, the user name is inserted into the
	`auth_cookie` table and a cookie identifying the user on subsequent
	requests is sent back to the client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web form 'username' variable
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """

        if req.args.get('username'):
            assert req.args.get('password'), 'No password'
            # Test authentication

            try:
                self._try_http_auth(
                    req.base_url[:req.base_url.find('/', 8)] + '/login',
                    req.args.get('username'), req.args.get('password'))
            except IOError, e:
                # Incorrect password
                req.hdf['title'] = 'Login Failed'
                req.hdf['login.action'] = self.env.href() + '/login'
                req.hdf['login.referer'] = req.args.get('ref')
                req.hdf['login.error'] = 'Invalid username or password'
                return None

            # Successful authentication, set cookies and stuff
            remote_user = req.args.get('username')
            ignore_case = self.env.config.get('trac', 'ignore_auth_case')
            ignore_case = ignore_case.strip().lower() in TRUE
            if ignore_case:
                remote_user = remote_user.lower()

            assert req.authname in ('anonymous', remote_user), \
                   'Already logged in as %s.' % req.authname

            cookie = hex_entropy()
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute(
                "INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                "VALUES (%s, %s, %s, %s)",
                (cookie, remote_user, req.remote_addr, int(time.time())))
            db.commit()

            req.authname = remote_user
            req.outcookie['trac_auth'] = cookie
            req.outcookie['trac_auth']['path'] = self.env.href()
            req.redirect(req.args.get('ref') or self.env.abs_href())
Beispiel #8
0
 def send_auth_request(self, environ, start_response, stale='false'):
     """Send a digest challange to the browser. Record used nonces
     to avoid replay attacks.
     """
     nonce = hex_entropy()
     self.active_nonces.append(nonce)
     if len(self.active_nonces) > self.MAX_NONCES:
         self.active_nonces = self.active_nonces[-self.MAX_NONCES:]
     start_response('401 Unauthorized',
                    [('WWW-Authenticate',
                     'Digest realm="%s", nonce="%s", qop="auth", stale="%s"'
                     % (self.realm, nonce, stale))])('')
Beispiel #9
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        if not req.remote_user:
            # TRANSLATOR: ... refer to the 'installation documentation'. (link)
            inst_doc = tag.a(_('installation documentation'),
                             title=_("Configuring Authentication"),
                             href=req.href.wiki('TracInstall') +
                             "#ConfiguringAuthentication")
            raise TracError(
                tag_(
                    "Authentication information not available. "
                    "Please refer to the %(inst_doc)s.",
                    inst_doc=inst_doc))
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ('anonymous', remote_user), \
               _('Already logged in as %(user)s.', user=req.authname)

        cookie = hex_entropy()

        @self.env.with_transaction()
        def store_session_cookie(db):
            cursor = db.cursor()
            # Delete cookies older than 10 days
            cursor.execute("DELETE FROM auth_cookie WHERE time < %s",
                           (int(time.time()) - 86400 * 10, ))
            cursor.execute(
                "INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                "VALUES (%s, %s, %s, %s)",
                (cookie, remote_user, req.remote_addr, int(time.time())))

        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = self.auth_cookie_path \
                                             or req.base_path or '/'
        if self.env.secure_cookies:
            req.outcookie['trac_auth']['secure'] = True
        if self.auth_cookie_lifetime > 0:
            req.outcookie['trac_auth']['expires'] = self.auth_cookie_lifetime
Beispiel #10
0
 def send_auth_request(self, environ, start_response, stale='false'):
     """Send a digest challange to the browser. Record used nonces
     to avoid replay attacks.
     """
     nonce = hex_entropy()
     self.active_nonces.append(nonce)
     if len(self.active_nonces) > self.MAX_NONCES:
         self.active_nonces = self.active_nonces[-self.MAX_NONCES:]
     start_response('401 Unauthorized',
                    [('WWW-Authenticate',
                     'Digest realm="%s", nonce="%s", qop="auth", stale="%s"'
                     % (self.realm, nonce, stale))])('')
Beispiel #11
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        if not req.remote_user:
            # TRANSLATOR: ... refer to the 'installation documentation'. (link)
            inst_doc = tag.a(
                _("installation documentation"),
                title=_("Configuring Authentication"),
                href=req.href.wiki("TracInstall") + "#ConfiguringAuthentication",
            )
            raise TracError(
                tag_(
                    "Authentication information not available. " "Please refer to the %(inst_doc)s.", inst_doc=inst_doc
                )
            )
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ("anonymous", remote_user), _("Already logged in as %(user)s.", user=req.authname)

        cookie = hex_entropy()

        @self.env.with_transaction()
        def store_session_cookie(db):
            cursor = db.cursor()
            # Delete cookies older than 10 days
            cursor.execute("DELETE FROM auth_cookie WHERE time < %s", (int(time.time()) - 86400 * 10,))
            cursor.execute(
                "INSERT INTO auth_cookie (cookie,name,ipnr,time) " "VALUES (%s, %s, %s, %s)",
                (cookie, remote_user, req.remote_addr, int(time.time())),
            )

        req.authname = remote_user
        req.outcookie["trac_auth"] = cookie
        req.outcookie["trac_auth"]["path"] = self.auth_cookie_path or req.base_path or "/"
        if self.env.secure_cookies:
            req.outcookie["trac_auth"]["secure"] = True
        if self.auth_cookie_lifetime > 0:
            req.outcookie["trac_auth"]["expires"] = self.auth_cookie_lifetime
Beispiel #12
0
 def __init__(self, env, req):
     super(Session, self).__init__(env, None)
     self.req = req
     if req.authname == 'anonymous':
         if not req.incookie.has_key(COOKIE_KEY):
             self.sid = hex_entropy(24)
             self.bake_cookie()
         else:
             sid = req.incookie[COOKIE_KEY].value
             self.get_session(sid)
     else:
         if req.incookie.has_key(COOKIE_KEY):
             sid = req.incookie[COOKIE_KEY].value
             self.promote_session(sid)
         self.get_session(req.authname, authenticated=True)
Beispiel #13
0
 def __init__(self, env, req):
     super(Session, self).__init__(env, None)
     self.req = req
     if req.authname == 'anonymous':
         if not req.incookie.has_key(COOKIE_KEY):
             self.sid = hex_entropy(24)
             self.bake_cookie()
         else:
             sid = req.incookie[COOKIE_KEY].value
             self.get_session(sid)
     else:
         if req.incookie.has_key(COOKIE_KEY):
             sid = req.incookie[COOKIE_KEY].value
             self.promote_session(sid)
         self.get_session(req.authname, authenticated=True)
Beispiel #14
0
 def send_auth_request(self, req, stale='false'):
     """
     Send a digest challange to the browser. Record used nonces
     to avoid replay attacks.
     """
     nonce = util.hex_entropy()
     self.active_nonces.append(nonce)
     if len(self.active_nonces) > DigestAuth.MAX_NONCES:
         self.active_nonces = self.active_nonces[-DigestAuth.MAX_NONCES:]
     req.send_response(401)
     req.send_header(
         'WWW-Authenticate',
         'Digest realm="%s", nonce="%s", qop="auth", stale="%s"' %
         (self.realm, nonce, stale))
     req.end_headers()
Beispiel #15
0
 def __init__(self, env, req):
     super(Session, self).__init__(env, None)
     self.req = req
     if not req.is_authenticated:
         if COOKIE_KEY not in req.incookie:
             self.sid = hex_entropy(24)
             self.bake_cookie()
         else:
             sid = req.incookie[COOKIE_KEY].value
             self.get_session(sid)
     else:
         if COOKIE_KEY in req.incookie:
             sid = req.incookie[COOKIE_KEY].value
             self.promote_session(sid)
         self.get_session(req.authname, authenticated=True)
Beispiel #16
0
    def _get_form_token(self, req):
        """Used to protect against CSRF.

        The 'form_token' is strong shared secret stored in a user cookie.
        By requiring that every POST form to contain this value we're able to
        protect against CSRF attacks. Since this value is only known by the
        user and not by an attacker.
        
        If the the user does not have a `trac_form_token` cookie a new
        one is generated.
        """
        if req.incookie.has_key('trac_form_token'):
            return req.incookie['trac_form_token'].value
        else:
            req.outcookie['trac_form_token'] = hex_entropy(24)
            req.outcookie['trac_form_token']['path'] = req.base_path
            return req.outcookie['trac_form_token'].value
Beispiel #17
0
 def save(self, db=None):
     handle_commit = False
     if db is None:
         db = self.env.get_db_cnx()
         handle_commit = True
     cursor = db.cursor()
     
     if self.key is None:
         self.key = hex_entropy(16)
         
     if self.exists:
         cursor.execute('UPDATE tracbl_apikeys SET key=%s WHERE email=%s', (self.key, self.email)) # ???: Is this needed?
     else:
         cursor.execute('INSERT INTO tracbl_apikeys (email, key) VALUES (%s, %s)', (self.email, self.key))
         
     if handle_commit:
         db.commit()
Beispiel #18
0
    def _get_form_token(self, req):
        """Used to protect against CSRF.

        The 'form_token' is strong shared secret stored in a user cookie.
        By requiring that every POST form to contain this value we're able to
        protect against CSRF attacks. Since this value is only known by the
        user and not by an attacker.
        
        If the the user does not have a `trac_form_token` cookie a new
        one is generated.
        """
        if req.incookie.has_key('trac_form_token'):
            return req.incookie['trac_form_token'].value
        else:
            req.outcookie['trac_form_token'] = hex_entropy(24)
            req.outcookie['trac_form_token']['path'] = req.base_path
            return req.outcookie['trac_form_token'].value
Beispiel #19
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        if not req.remote_user:
            raise TracError(
                tag(
                    "Authentication information not available. " "Please refer to the ",
                    tag.a(
                        "installation documentation",
                        title="Configuring Authentication",
                        href=req.href.wiki("TracInstall") + "#ConfiguringAuthentication",
                    ),
                    ".",
                )
            )
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ("anonymous", remote_user), "Already logged in as %s." % req.authname

        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO auth_cookie (cookie,name,ipnr,time) " "VALUES (%s, %s, %s, %s)",
            (cookie, remote_user, req.remote_addr, int(time.time())),
        )
        db.commit()

        req.authname = remote_user
        req.outcookie["trac_auth"] = cookie
        req.outcookie["trac_auth"]["path"] = req.base_path or "/"
        if self.env.secure_cookies:
            req.outcookie["trac_auth"]["secure"] = True
Beispiel #20
0
 def __init__(self, env, req, newsession=False):
     dict.__init__(self)
     self.env = env
     self.req = req
     self.sid = None
     self._old = {}
     if req.authname == 'anonymous':
         if newsession or not req.incookie.has_key(COOKIE_KEY):
             self.sid = hex_entropy(24)
             self.bake_cookie()
         else:
             sid = req.incookie[COOKIE_KEY].value
             self.get_session(sid)
     else:
         if req.incookie.has_key(COOKIE_KEY):
             sid = req.incookie[COOKIE_KEY].value
             self.promote_session(sid)
         self.get_session(req.authname, authenticated=True)
Beispiel #21
0
    def _do_login(self, req, remote_user):
        """Log the remote user in."""

        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO auth_cookie "
                       "(cookie ,name ,ipnr ,time) "
                       "VALUES (%s, %s, %s, %s)",
                       (cookie, remote_user, req.remote_addr,
                        int(time.time())))
        db.commit()

        req.outcookie['db_auth'] = cookie
        req.outcookie['db_auth']['path'] = req.href()
        req.outcookie['db_auth']['expires'] = 100000000

        self._update_email(remote_user)
Beispiel #22
0
 def send_auth_request(self, environ, start_response, stale="false"):
     """Send a digest challange to the browser. Record used nonces
     to avoid replay attacks.
     """
     nonce = hex_entropy()
     self.active_nonces.append(nonce)
     if len(self.active_nonces) > self.MAX_NONCES:
         self.active_nonces = self.active_nonces[-self.MAX_NONCES :]
     start_response(
         "401 Unauthorized",
         [
             (
                 "WWW-Authenticate",
                 'Digest realm="%s", nonce="%s", qop="auth", stale="%s"' % (self.realm, nonce, stale),
             ),
             ("Content-Length", "0"),
         ],
     )("")
Beispiel #23
0
    def _do_login(self, req):
        """Log the remote user in."""
        
        remote_user, pwd = req.args.get('uid'), req.args.get('pwd')
        remote_user = remote_user.lower()

        cookie = hex_entropy()
        db = get_db(self.env)
        cursor = db.cursor()
        cursor.execute("INSERT INTO trac_cookies "
                       "(envname, cookie, username, ipnr, unixtime) "
                       "VALUES (%s, %s, %s, %s, %s)", (self.envname, cookie, remote_user,
                       req.remote_addr, int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_db_auth'] = cookie
        req.outcookie['trac_db_auth']['expires'] = 100000000
        req.outcookie['trac_db_auth']['path'] = self.env.href()
Beispiel #24
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        if not req.remote_user:
            raise TracError(
                html(
                    u"Pas d'information d'authentification disponible. "
                    u"Merci de vous référer à la ",
                    html.a(u"documentation d'installation",
                           title="Configuration de l'authentification",
                           href=req.href.wiki('TracInstall') +
                           "#ConfiguringAuthentication"), "."))
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ('anonymous', remote_user), \
               u'Déjà connecté sous %s.' % req.authname

        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO auth_cookie (cookie,name,ipnr,time) "
            "VALUES (%s, %s, %s, %s)",
            (cookie, remote_user, req.remote_addr, int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = req.href()
Beispiel #25
0
    def save(self, db=None):
        handle_commit = False
        if db is None:
            db = self.env.get_db_cnx()
            handle_commit = True
        cursor = db.cursor()

        if self.key is None:
            self.key = hex_entropy(16)

        if self.exists:
            cursor.execute('UPDATE tracbl_apikeys SET key=%s WHERE email=%s',
                           (self.key, self.email))  # ???: Is this needed?
        else:
            cursor.execute(
                'INSERT INTO tracbl_apikeys (email, key) VALUES (%s, %s)',
                (self.email, self.key))

        if handle_commit:
            db.commit()
Beispiel #26
0
    def __init__(self, env, req):
        super(Session, self).__init__(env, None)
        self.req = req
	
	if req.incookie:
	  sid = ''
	  need_bake = False
	  
	  if not req.incookie.has_key(COOKIE_KEY):
	    sid = hex_entropy(32)
	    need_bake = True
	  else:
	    sid = req.incookie[COOKIE_KEY].value
	  
	  self.get_session(sid)

	  if need_bake or sid != self.sid:
	    self.bake_cookie()
	else:
	  env.log.warning('no incookie')
Beispiel #27
0
    def _create_auth_cookie(self, req, remote_user):
        cookie = hex_entropy()

        sql = """
        INSERT IGNORE INTO auth_cookie (cookie, name, ipnr, time)
        VALUES (%s, %s, %s, %s)
        """
        with admin_transaction() as cursor:
            try:
                cursor.execute(sql, (cookie, remote_user, req.remote_addr, int(time.time())))
            except Exception:
                self.log.exception("Failed to store auth cookie into database")
                raise

        # Make new cookie
        self._set_outcookie(req, cookie)

        # Create cached cookie
        self.cookie.add(cookie)
        return cookie
Beispiel #28
0
 def __init__(self, env, req):
     dict.__init__(self)
     self.env = env
     self.req = req
     self.sid = None
     self.last_visit = 0
     self._new = True
     self._old = {}
     if req.authname == 'anonymous':
         if not req.incookie.has_key(COOKIE_KEY):
             self.sid = hex_entropy(24)
             self.bake_cookie()
         else:
             sid = req.incookie[COOKIE_KEY].value
             self.get_session(sid)
     else:
         if req.incookie.has_key(COOKIE_KEY):
             sid = req.incookie[COOKIE_KEY].value
             self.promote_session(sid)
         self.get_session(req.authname, authenticated=True)
Beispiel #29
0
    def html_to_pdf(self, req, html_pages, book=True, title='', subject='', version='', date=''):
        
        self.env.log.debug('WikiPrint => Start function html_to_pdf')

        page = Markup('\n<div><pdf:nextpage /></div>'.join(html_pages))
        
        #Replace PageOutline macro with Table of Contents
        if book:
            #If book, remove [[TOC]], and add at beginning
            page = page.replace('[[pdf-toc]]','')
            page = Markup(self.get_toc()) + Markup(page)
        else:
            page = page.replace('[[pdf-toc]]',self.get_toc())

        page = self.add_headers(req, page, book, title=title, subject=subject, version=version, date=date)
        page = page.encode(self.default_charset, 'replace')
        css_data = self.get_css(req)

        pdf_file = StringIO.StringIO()

        auth_cookie = hex_entropy()
        loader = linkLoader(self.env, req, auth_cookie)

        #Temporary authentication
        self.env.log.debug("Storing temporary auth cookie %s for user %s", auth_cookie, req.authname)
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
            "VALUES (%s, %s, %s, %s)", (auth_cookie, req.authname, '127.0.0.1', int(time.time())))
        db.commit()        
        
        pdf = pisa.CreatePDF(page, pdf_file, show_errors_as_pdf = True, default_css = css_data, link_callback = loader.getFileName)
        out = pdf_file.getvalue()
        pdf_file.close()
        
        cursor.execute("DELETE FROM auth_cookie WHERE cookie=%s", (auth_cookie,))
        db.commit()        

        self.env.log.debug('WikiPrint => Finish function html_to_pdf')

        return out
Beispiel #30
0
    def _get_form_token(self, req):
        """Used to protect against CSRF.

        The 'form_token' is strong shared secret stored in a user
        cookie.  By requiring that every POST form to contain this
        value we're able to protect against CSRF attacks. Since this
        value is only known by the user and not by an attacker.

        If the the user does not have a `trac_form_token` cookie a new
        one is generated.
        """
        if 'trac_form_token' in req.incookie:
            return req.incookie['trac_form_token'].value
        else:
            req.outcookie['trac_form_token'] = hex_entropy(24)
            req.outcookie['trac_form_token']['path'] = req.base_path or '/'
            if self.env.secure_cookies:
                req.outcookie['trac_form_token']['secure'] = True
            if sys.version_info >= (2, 6):
                req.outcookie['trac_form_token']['httponly'] = True
            return req.outcookie['trac_form_token'].value
Beispiel #31
0
    def _get_form_token(self, req):
        """Used to protect against CSRF.

        The 'form_token' is strong shared secret stored in a user
        cookie.  By requiring that every POST form to contain this
        value we're able to protect against CSRF attacks. Since this
        value is only known by the user and not by an attacker.

        If the the user does not have a `trac_form_token` cookie a new
        one is generated.
        """
        if 'trac_form_token' in req.incookie:
            return req.incookie['trac_form_token'].value
        else:
            req.outcookie['trac_form_token'] = hex_entropy(24)
            req.outcookie['trac_form_token']['path'] = req.base_path or '/'
            if self.env.secure_cookies:
                req.outcookie['trac_form_token']['secure'] = True
            if sys.version_info >= (2, 6):
                req.outcookie['trac_form_token']['httponly'] = True
            return req.outcookie['trac_form_token'].value
Beispiel #32
0
    def _login(self, req, response):
        """Store login information into session."""
        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO auth_cookie " "(cookie ,name ,ipnr ,time) " "VALUES (%s, %s, %s, %s)",
            (cookie, response.identity_url, req.remote_addr, int(time.time())),
        )
        db.commit()

        req.outcookie["trac_auth"] = cookie
        req.outcookie["trac_auth"]["path"] = self.env.href()
        req.outcookie["trac_auth"]["expires"] = 60 * 60 * 24

        # update user's contact details
        info = response.extensionResponse("sreg")
        if info and info.has_key("fullname") and len(info["fullname"]) > 0:
            req.session["name"] = info["fullname"]
        if info and info.has_key("email") and len(info["email"]) > 0:
            req.session["email"] = info["email"]
Beispiel #33
0
    def _do_login(self, req):
        """Log the remote user in."""

        remote_user, pwd = req.args.get('uid'), req.args.get('pwd')
        remote_user = remote_user.lower()

        cookie = hex_entropy()
        db = get_db(self.env)
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO trac_cookies "
            "(envname, cookie, username, ipnr, unixtime) "
            "VALUES (%s, %s, %s, %s, %s)",
            (self.envname, cookie, remote_user, req.remote_addr,
             int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_db_auth'] = cookie
        req.outcookie['trac_db_auth']['expires'] = 100000000
        req.outcookie['trac_db_auth']['path'] = self.env.href()
Beispiel #34
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        if not req.remote_user:
            raise TracError(html(u"Pas d'information d'authentification disponible. "
                                 u"Merci de vous référer à la ",
                                 html.a(u"documentation d'installation",
                                        title="Configuration de l'authentification",
                                        href=req.href.wiki('TracInstall') +
                                        "#ConfiguringAuthentication"), "."))
        remote_user = req.remote_user
        if self.ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ('anonymous', remote_user), \
               u'Déjà connecté sous %s.' % req.authname

        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                       "VALUES (%s, %s, %s, %s)", (cookie, remote_user,
                       req.remote_addr, int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = req.href()
Beispiel #35
0
    def _write_module(self, version, url):
        modname = 'TestModule_' + util.hex_entropy(16)
        modpath = os.path.join(self.dir, modname + '.py')
        with open(modpath, 'w', encoding='utf-8') as f:
            f.write(textwrap.dedent("""\
                # -*- coding: utf-8 -*-
                from trac.core import Component

                version = '%s'
                author = 'Joe'
                author_email = '*****@*****.**'
                maintainer = 'Jim'
                maintainer_email = '*****@*****.**'
                home_page = '%s'
                license = 'BSD 3-Clause'
                summary = 'summary.'
                trac = 'http://my.trac.com'

                class TestModule(Component):
                    pass
                """) % (version, url))
        return modname
Beispiel #36
0
    def _login(self, req, response):
        """Store login information into session."""
        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute('INSERT INTO auth_cookie ' \
                       '(cookie ,name ,ipnr ,time) ' \
                       'VALUES (%s, %s, %s, %s)',
                       (cookie, response.identity_url,
                        req.remote_addr, int(time.time())))
        db.commit()

        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = self.env.href()
        req.outcookie['trac_auth']['expires'] = 60 * 60 * 24

        # update user's contact details
        info = response.extensionResponse('sreg')
        if info and info.has_key('fullname') and len(info['fullname']) > 0:
            req.session['name'] = info['fullname']
        if info and info.has_key('email') and len(info['email']) > 0:
            req.session['email'] = info['email']
Beispiel #37
0
    def _do_login(self, req):
        """Log the remote user in."""

        remote_user = req.args.get('uid')
        remote_user = remote_user.lower()

        cookie = hex_entropy()
        db = get_db(self.env)
        cursor = db.cursor()
        sql = "INSERT INTO %s " \
              "(%s, %s, %s, %s, %s) " \
              "VALUES (%%s, %%s, %%s, %%s, %%s)" % \
              (self.cookies['table'], self.cookies['envname'], 
               self.cookies['cookie'], self.cookies['username'], 
               self.cookies['ipnr'], self.cookies['unixtime'])
        cursor.execute(sql, (self.envname, cookie, remote_user, 
                        req.remote_addr, int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_db_auth'] = cookie
        req.outcookie['trac_db_auth']['expires'] = 100000000
        req.outcookie['trac_db_auth']['path'] = self.env.href()
Beispiel #38
0
    def _do_login(self, req):
        """Log the remote user in.

        This function expects to be called when the remote user name is
        available. The user name is inserted into the `auth_cookie` table and a
        cookie identifying the user on subsequent requests is sent back to the
        client.

        If the Authenticator was created with `ignore_case` set to true, then 
        the authentication name passed from the web server in req.remote_user
        will be converted to lower case before being used. This is to avoid
        problems on installations authenticating against Windows which is not
        case sensitive regarding user names and domain names
        """
        assert req.remote_user, 'Authentication information not available.'

        remote_user = req.remote_user
        ignore_case = self.env.config.get('trac', 'ignore_auth_case')
        ignore_case = ignore_case.strip().lower() in TRUE
        if ignore_case:
            remote_user = remote_user.lower()

        assert req.authname in ('anonymous', remote_user), \
               'Already logged in as %s.' % req.authname

        cookie = hex_entropy()
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                       "VALUES (%s, %s, %s, %s)", (cookie, remote_user,
                       req.remote_addr, int(time.time())))
        db.commit()

        req.authname = remote_user
        req.outcookie['trac_auth'] = cookie
        req.outcookie['trac_auth']['path'] = self.env.href()
 def get_auth_url(self, req):
     flow = self.flow
     state = hex_entropy()
     req.session[self.STATE_SKEY] = state
     flow.params['state'] = state
     return flow.step1_get_authorize_url()
Beispiel #40
0
 def test_hex_entropy(self):
     """hex_entropy() not affected by global random generator state"""
     random.seed(0)
     data = util.hex_entropy(64)
     random.seed(0)
     self.assertNotEqual(data, util.hex_entropy(64))
Beispiel #41
0
    def _do_process(self, req):
        """Handle the redirect from the OpenID server.
        """
        db = self.env.get_db_cnx()
        oidconsumer, session = self._get_consumer(req, db)

        # Ask the library to check the response that the server sent
        # us.  Status is a code indicating the response type. info is
        # either None or a string containing more information about
        # the return type.
        info = oidconsumer.complete(req.args,req.args['openid.return_to'])

        css_class = 'error'
        if info.status == consumer.FAILURE and info.identity_url:
            # In the case of failure, if info is non-None, it is the
            # URL that we were verifying. We include it in the error
            # message to help the user figure out what happened.
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url),
                             info.message)
        elif info.status == consumer.SUCCESS:
            # Success means that the transaction completed without
            # error. If info is None, it means that the user cancelled
            # the verification.
            css_class = 'alert'

            # This is a successful verification attempt. If this
            # was a real application, we would do our login,
            # comment posting, etc. here.
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url),)
            remote_user = info.identity_url

            sreg_info = sreg.SRegResponse.fromSuccessResponse(info) or {}

            ax_response = ax.FetchResponse.fromSuccessResponse(info)
            ax_info = {}
            if ax_response:
                for alias, uri in self.openid_ax_attrs.items():
                    values = ax_response.data.get(uri,[])
                    if values:
                        ax_info[alias] = values[0]

            email = (ax_info.get('email')
                     or ax_info.get('email2')
                     or sreg_info.get('email'))

            fullname = (' '.join(filter(None, map(ax_info.get,
                                                  ('firstname', 'lastname'))))
                        or sreg_info.get('fullname')
                        or email.split('@',1)[0].replace('.', ' ').title())

            if self.strip_protocol:
                remote_user = remote_user[remote_user.find('://')+3:]
            if self.strip_trailing_slash and remote_user[-1] == '/':
                remote_user = remote_user[:-1]
            if info.endpoint.canonicalID:
                # You should authorize i-name users by their canonicalID,
                # rather than their more human-friendly identifiers.  That
                # way their account with you is not compromised if their
                # i-name registration expires and is bought by someone else.
                message += ("  This is an i-name, and its persistent ID is %s"
                            % (cgi.escape(info.endpoint.canonicalID),))
                remote_user = info.endpoint.canonicalID

            allowed = True
            if self.re_white_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through white-list." % remote_user)
                allowed = False
                for item in self.re_white_list:
                    if not allowed and item.match(remote_user):
                        allowed = True
                        self.env.log.debug("User white-listed.")
            if allowed and self.re_black_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through black-list." % remote_user)
                for item in self.re_black_list:
                    if item.match(remote_user):
                        allowed = False
                        self.env.log.debug("User black-listed.")
            if allowed and email and self.re_email_white_list:
                self.env.log.debug("Filtering email '%s' through email white-list." % email)
                allowed = False
                for item in self.re_email_white_list:
                    if not allowed and item.match(email):
                        allowed = True
                        self.env.log.debug("User email white-listed.")

            if allowed and self.check_list:
                params = {self.check_list_key: remote_user}
                if email:
                    params['email'] = email
                url = self.check_list + '?' + urllib.urlencode(params)
                self.env.log.debug('OpenID check list URL: %s' % url)
                result = json.load(urllib.urlopen(url))
                if not result[self.check_list_key]:
                    allowed = False
                elif self.check_list_username:
                    new_user = result[self.check_list_username]
                    if new_user:
                        remote_user = new_user

            if allowed:
                cookie = hex_entropy()
                cookie_lifetime = self.trac_auth_cookie_lifetime

                req.outcookie['trac_auth'] = cookie
                req.outcookie['trac_auth']['path'] = req.href()
                if cookie_lifetime > 0:
                    req.outcookie['trac_auth']['expires'] = cookie_lifetime

                req.session[self.openid_session_identity_url_key] = info.identity_url
                if email:
                    req.session['email'] = email
                if fullname:
                    req.session['name'] = fullname

                self._commit_session(session, req)

                if req.session.get('name'):
                    authname = req.session['name']
                    if self.combined_username:
                        authname = '%s <%s>' % (authname, remote_user)

                # Possibly lower-case the authname.
                if self.lowercase_authname:
                    authname = authname.lower()

                # Make authname unique in case of collisions
                #
                # XXX: We ought to first look for an existing authenticated
                # ssession with matching identity_url, and just use that
                # for the authid.  (E.g. what if the user changes his
                # fullname at the openid provider?)  However, trac does
                # not seem to provide an API for searching sessions other
                # than by sid/authname.
                #
                def authnames(base):
                    yield base
                    for attempt in itertools.count(2):
                        yield "%s (%d)" % (base, attempt)

                for authname in authnames(authname):
                    ds = DetachedSession(self.env, authname)
                    if ds.last_visit == 0 and len(ds) == 0:
                        # At least in 0.12.2, this mean no session exists.
                        break
                    ds_identity = ds.get(self.openid_session_identity_url_key)
                    if ds_identity == info.identity_url:
                        # No collision
                        break

                req.authname = authname

                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                               "VALUES (%s, %s, %s, %s)", (cookie, authname,
                               self._get_masked_address(req.remote_addr), int(time.time())))
                db.commit()

                req.redirect(req.session.get('oid.referer') or self.env.abs_href())
            else:
                message = 'You are not allowed here.'
        elif info.status == consumer.CANCEL:
            # cancelled
            message = 'Verification cancelled'
        elif info.status == consumer.SETUP_NEEDED:
            if info.setup_url:
                message = '<a href=%s>Setup needed</a>' % (
                    quoteattr(info.setup_url),)
            else:
                # This means auth didn't succeed, but you're welcome to try
                # non-immediate mode.
                message = 'Setup needed'
        else:
            # Either we don't understand the code or there is no
            # openid_url included with the error. Give a generic
            # failure message. The library should supply debug
            # information in a log.
            message = 'Verification failed.'

        self._commit_session(session, req)

        add_stylesheet(req, 'authopenid/css/openid.css')
        add_script(req, 'authopenid/js/openid-jquery.js')
        return 'openidlogin.html', {
            'images': req.href.chrome('authopenid/images') + '/',
            'action': req.href.openidverify(),
            'message': message,
            'signup': self.signup_link,
            'whatis': self.whatis_link,
            'css_class': css_class,
            'providers_regexp': self.providers_regexp,
            'custom_provider_name': self.custom_provider_name,
            'custom_provider_label': self.custom_provider_label,
            'custom_provider_url': self.custom_provider_url,
            'custom_provider_image': self.custom_provider_image,
            'custom_provider_size': self.custom_provider_size,
            }, None
Beispiel #42
0
    def _get_name_for_cookie(self, req, cookie):
        """Returns the user name for the current Trac session.

        It's called by authenticate() when the cookie 'trac_auth' is sent
        by the browser.
        """

        acctmgr = AccountManager(self.env)

        # Disable IP checking when a persistent session is available, as the
        # user may have a dynamic IP adress and this would lead to the user 
        # being logged out due to an IP address conflict.
        checkIPSetting = self.check_ip and acctmgr.persistent_sessions and \
                         'trac_auth_session' in req.incookie
        if checkIPSetting:
            self.env.config.set('trac', 'check_auth_ip', False)
        
        name = auth.LoginModule._get_name_for_cookie(self, req, cookie)
        
        if checkIPSetting:
            # Re-enable IP checking
            self.env.config.set('trac', 'check_auth_ip', True)
        
        if acctmgr.persistent_sessions and name and \
                'trac_auth_session' in req.incookie and \
                int(req.incookie['trac_auth_session'].value) < \
                int(time.time()) - self.UPDATE_INTERVAL:
            # Persistent sessions enabled, the user is logged in
            # ('name' exists) and has actually decided to use this feature
            # (indicated by the 'trac_auth_session' cookie existing).
            # 
            # NOTE: This method is called on every request.
            
            # Refresh session cookie
            # Update the timestamp of the session so that it doesn't expire.
            self.env.log.debug('Updating session %s for user %s' %
                                (cookie.value, name))
            # Refresh in database
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute("""
                UPDATE  auth_cookie
                    SET time=%s
                WHERE   cookie=%s
                """, (int(time.time()), cookie.value))
            db.commit()

            # Change session ID (cookie.value) now and then as it otherwise
            #   never would change at all (i.e. stay the same indefinitely and
            #   therefore is more vulnerable to be hacked).
            if random.random() + self.cookie_refresh_pct / 100.0 > 1:
                old_cookie = cookie.value
                # Update auth cookie value
                cookie.value = hex_entropy()
                self.env.log.debug('Changing session id for user %s to %s'
                                    % (name, cookie.value))
                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute("""
                    UPDATE  auth_cookie
                        SET cookie=%s
                    WHERE   cookie=%s
                    """, (cookie.value, old_cookie))
                db.commit()
                self._distribute_cookie(req, cookie.value)

            cookie_lifetime = self.cookie_lifetime
            cookie_path = self._get_cookie_path(req)
            req.outcookie['trac_auth'] = cookie.value
            req.outcookie['trac_auth']['path'] = cookie_path
            req.outcookie['trac_auth']['expires'] = cookie_lifetime
            req.outcookie['trac_auth_session'] = int(time.time())
            req.outcookie['trac_auth_session']['path'] = cookie_path
            req.outcookie['trac_auth_session']['expires'] = cookie_lifetime
            try:
                if self.env.secure_cookies:
                    req.outcookie['trac_auth']['secure'] = True
                    req.outcookie['trac_auth_session']['secure'] = True
            except AttributeError:
                # Report details about Trac compatibility for the feature.
                self.env.log.debug(
                    """Restricting cookies to HTTPS connections is requested,
                    but is supported only by Trac 0.11.2 or later version.
                    """)
        return name
Beispiel #43
0
    def _do_process(self, req):
        """Handle the redirect from the OpenID server.
        """
        db = self.env.get_db_cnx()
        oidconsumer, oidsession = self._get_consumer(req, db)

        # Ask the library to check the response that the server sent
        # us.  Status is a code indicating the response type. info is
        # either None or a string containing more information about
        # the return type.
        info = oidconsumer.complete(req.args, req.args['openid.return_to'])

        css_class = 'error'
        if info.status == consumer.FAILURE and info.identity_url:
            # In the case of failure, if info is non-None, it is the
            # URL that we were verifying. We include it in the error
            # message to help the user figure out what happened.
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url), info.message)
        elif info.status == consumer.SUCCESS:
            # Success means that the transaction completed without
            # error. If info is None, it means that the user cancelled
            # the verification.
            css_class = 'alert'

            session_attr = {}  # attributes for new "user"

            # This is a successful verification attempt. If this
            # was a real application, we would do our login,
            # comment posting, etc. here.
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url), )
            remote_user = info.identity_url

            sreg_info = sreg.SRegResponse.fromSuccessResponse(info) or {}

            ax_response = ax.FetchResponse.fromSuccessResponse(info)
            ax_info = {}
            if ax_response:
                for alias, uri in self.openid_ax_attrs.items():
                    values = ax_response.data.get(uri, [])
                    if values:
                        ax_info[alias] = values[0]

            email = (ax_info.get('email') or ax_info.get('email2')
                     or sreg_info.get('email'))

            fullname = (' '.join(
                filter(None, map(ax_info.get, ('firstname', 'lastname'))))
                        or sreg_info.get('fullname') or
                        (email
                         and email.split('@', 1)[0].replace('.', ' ').title()))

            nickname = sreg_info.get('nickname')

            if self.groups_to_request and TeamsResponse:
                teams_response = TeamsResponse.fromSuccessResponse(info)
                if teams_response:
                    # be careful not to make user a member of any trac groups
                    # not named in groups_to_request
                    teams = set(teams_response.teams).intersection(
                        self.groups_to_request)
                    if teams:
                        session_attr['openid.teams'] = ','.join(teams)

            if self.strip_protocol:
                remote_user = remote_user[remote_user.find('://') + 3:]
            if self.strip_trailing_slash and remote_user[-1] == '/':
                remote_user = remote_user[:-1]
            if info.endpoint.canonicalID:
                # You should authorize i-name users by their canonicalID,
                # rather than their more human-friendly identifiers.  That
                # way their account with you is not compromised if their
                # i-name registration expires and is bought by someone else.
                message += (
                    "  This is an i-name, and its persistent ID is %s" %
                    (cgi.escape(info.endpoint.canonicalID), ))
                remote_user = info.endpoint.canonicalID

            allowed = True
            if self.re_white_list:
                self.env.log.debug(
                    "Filtering REMOTE_USER '%s' through white-list." %
                    remote_user)
                allowed = False
                for item in self.re_white_list:
                    if not allowed and item.match(remote_user):
                        allowed = True
                        self.env.log.debug("User white-listed.")
            if allowed and self.re_black_list:
                self.env.log.debug(
                    "Filtering REMOTE_USER '%s' through black-list." %
                    remote_user)
                for item in self.re_black_list:
                    if item.match(remote_user):
                        allowed = False
                        self.env.log.debug("User black-listed.")
            if allowed and self.re_email_white_list:
                self.env.log.debug(
                    "Filtering email %r through email white-list." % email)
                allowed = False
                if email:
                    for item in self.re_email_white_list:
                        if not allowed and item.match(email):
                            allowed = True
                            self.env.log.debug("User email white-listed.")

            if allowed and self.check_list:
                allowed = False
                params = {self.check_list_key: remote_user}
                if email:
                    params['email'] = email
                url = self.check_list + '?' + urllib.urlencode(params)
                self.env.log.debug('OpenID check list URL: %s' % url)
                try:
                    result = json.load(urllib.urlopen(url))
                    if result[self.check_list_key]:
                        if self.check_list_username:
                            cl_username = unicode(
                                result[self.check_list_username])
                            if not cl_username:
                                raise ValueError("Bad value for username")
                        allowed = True
                except Exception, ex:
                    self.env.log.error('OpenID check_list failed: %s' % ex)

            if allowed:
                cookie = hex_entropy()
                cookie_lifetime = self.trac_auth_cookie_lifetime

                req.outcookie['trac_auth'] = cookie
                req.outcookie['trac_auth']['path'] = req.href()
                if cookie_lifetime > 0:
                    req.outcookie['trac_auth']['expires'] = cookie_lifetime

                session_attr[
                    self.openid_session_identity_url_key] = info.identity_url
                if email:
                    session_attr['email'] = email
                if fullname:
                    session_attr['name'] = fullname

                self._commit_oidsession(oidsession, req)

                if self.check_list and self.check_list_username:
                    authname = cl_username
                elif self.use_nickname_as_authname and nickname:
                    authname = nickname
                elif session_attr.get('name'):
                    authname = session_attr['name']
                    if self.combined_username:
                        authname = '%s <%s>' % (authname, remote_user)
                else:
                    authname = remote_user

                # Possibly lower-case the authname.
                if self.lowercase_authname:
                    authname = authname.lower()

                if self.trust_authname:
                    ds = DetachedSession(self.env, authname)
                else:
                    # Make authname unique in case of collisions
                    #
                    # XXX: We ought to first look for an existing authenticated
                    # session with matching identity_url, and just use that
                    # for the authid.  (E.g. what if the user changes his
                    # fullname at the openid provider?)  However, trac does
                    # not seem to provide an API for searching sessions other
                    # than by sid/authname.
                    #
                    def authnames(base):
                        yield base
                        for attempt in itertools.count(2):
                            yield "%s (%d)" % (base, attempt)

                    existing_users_and_groups = set(
                        user for user, perm in PermissionSystem(
                            self.env).get_all_permissions())

                    for authname in authnames(authname):
                        ds = DetachedSession(self.env, authname)
                        if ds.last_visit == 0 and len(ds) == 0:
                            # At least in 0.12.2, this mean no session exists.
                            if authname in existing_users_and_groups:
                                # Permissions are already defined for this user
                                continue
                            break
                        ds_identity = ds.get(
                            self.openid_session_identity_url_key)
                        if ds_identity == info.identity_url:
                            # No collision
                            break

                if ds and (ds.last_visit != 0 or len(ds) > 0):
                    # The user already exists, update team membership
                    # XXX: Should also update name and/or email? (This would
                    # be an API change.)
                    for name in ['openid.teams']:
                        if name in session_attr:
                            ds[name] = session_attr[name]
                        elif name in ds:
                            del ds[name]
                    ds.save()
                else:
                    # We are creating a new "user".  Set attributes on the
                    # current anonymous session.  It will be promoted to
                    # the new authenticated session on the next request
                    # (by Session.__init__).
                    #
                    # NB: avoid dict.update here to ensure that
                    # DetachedSession.__getitem__ gets a chance to
                    # normalize values
                    for name, value in session_attr.items():
                        req.session[name] = value

                req.authname = authname

                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute(
                    "INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                    "VALUES (%s, %s, %s, %s)",
                    (cookie, authname, self._get_masked_address(
                        req.remote_addr), int(time.time())))
                db.commit()

                req.redirect(
                    req.session.get('oid.referer') or self.env.abs_href())
            else:
                message = 'You are not allowed here.'
Beispiel #44
0
    def _get_name_for_cookie(self, req, cookie):
        """Returns the username for the current Trac session.

        It's called by authenticate() when the cookie 'trac_auth' is sent
        by the browser.
        """

        acctmgr = AccountManager(self.env)
        name = None
        # Replicate _get_name_for_cookie() or _cookie_to_name() since Trac 1.0
        # adding special handling of persistent sessions, as the user may have
        # a dynamic IP adress and this would lead to the user being logged out
        # due to an IP address conflict.
        if 'trac_auth_session' in req.incookie or True:
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            sql = "SELECT name FROM auth_cookie WHERE cookie=%s AND ipnr=%s"
            args = (cookie.value, req.remote_addr)
            if acctmgr.persistent_sessions or not self.check_ip:
                sql = "SELECT name FROM auth_cookie WHERE cookie=%s"
                args = (cookie.value, )
            cursor.execute(sql, args)
            name = cursor.fetchone()
            name = name and name[0] or None
        if name is None:
            self._expire_cookie(req)

        if acctmgr.persistent_sessions and name and \
                'trac_auth_session' in req.incookie and \
                int(req.incookie['trac_auth_session'].value) < \
                int(time.time()) - self.UPDATE_INTERVAL:
            # Persistent sessions enabled, the user is logged in
            # ('name' exists) and has actually decided to use this feature
            # (indicated by the 'trac_auth_session' cookie existing).
            #
            # NOTE: This method is called on every request.

            # Refresh session cookie
            # Update the timestamp of the session so that it doesn't expire.
            self.env.log.debug('Updating session %s for user %s' %
                               (cookie.value, name))
            # Refresh in database
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute(
                """
                UPDATE  auth_cookie
                    SET time=%s
                WHERE   cookie=%s
                """, (int(time.time()), cookie.value))
            db.commit()

            # Change session ID (cookie.value) now and then as it otherwise
            #   never would change at all (i.e. stay the same indefinitely and
            #   therefore is more vulnerable to be hacked).
            if random.random() + self.cookie_refresh_pct / 100.0 > 1:
                old_cookie = cookie.value
                # Update auth cookie value
                cookie.value = hex_entropy()
                self.env.log.debug('Changing session id for user %s to %s' %
                                   (name, cookie.value))
                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute(
                    """
                    UPDATE  auth_cookie
                        SET cookie=%s
                    WHERE   cookie=%s
                    """, (cookie.value, old_cookie))
                db.commit()
                if self.auth_cookie_path:
                    self._distribute_auth(req, cookie.value, name)

            cookie_lifetime = self.cookie_lifetime
            cookie_path = self._get_cookie_path(req)
            req.outcookie['trac_auth'] = cookie.value
            req.outcookie['trac_auth']['path'] = cookie_path
            req.outcookie['trac_auth']['expires'] = cookie_lifetime
            req.outcookie['trac_auth_session'] = int(time.time())
            req.outcookie['trac_auth_session']['path'] = cookie_path
            req.outcookie['trac_auth_session']['expires'] = cookie_lifetime
            try:
                if self.env.secure_cookies:
                    req.outcookie['trac_auth']['secure'] = True
                    req.outcookie['trac_auth_session']['secure'] = True
            except AttributeError:
                # Report details about Trac compatibility for the feature.
                self.env.log.debug(
                    """Restricting cookies to HTTPS connections is requested,
                    but is supported only by Trac 0.11.2 or later version.
                    """)
        return name
Beispiel #45
0
    def html_to_pdf(self,
                    req,
                    html_pages,
                    book=True,
                    title='',
                    subject='',
                    version='',
                    date=''):

        self.env.log.debug('WikiPrint => Start function html_to_pdf')

        page = Markup('\n<div><pdf:nextpage /></div>'.join(html_pages))

        #Replace PageOutline macro with Table of Contents
        if book:
            #If book, remove [[TOC]], and add at beginning
            page = page.replace('[[pdf-toc]]', '')
            page = Markup(self.get_toc()) + Markup(page)
        else:
            page = page.replace('[[pdf-toc]]', self.get_toc())

        page = self.add_headers(req,
                                page,
                                book,
                                title=title,
                                subject=subject,
                                version=version,
                                date=date)
        page = page.encode(self.default_charset, 'replace')
        css_data = self.get_css(req)

        pdf_file = StringIO.StringIO()

        auth_cookie = hex_entropy()
        loader = linkLoader(self.env, req, auth_cookie)

        #Temporary authentication
        self.env.log.debug("Storing temporary auth cookie %s for user %s",
                           auth_cookie, req.authname)
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO auth_cookie (cookie,name,ipnr,time) "
            "VALUES (%s, %s, %s, %s)",
            (auth_cookie, req.authname, '127.0.0.1', int(time.time())))
        db.commit()

        pdf = pisa.CreatePDF(page,
                             pdf_file,
                             show_errors_as_pdf=True,
                             default_css=css_data,
                             link_callback=loader.getFileName)
        out = pdf_file.getvalue()
        pdf_file.close()

        cursor.execute("DELETE FROM auth_cookie WHERE cookie=%s",
                       (auth_cookie, ))
        db.commit()

        self.env.log.debug('WikiPrint => Finish function html_to_pdf')

        return out
 def new_biff_key(self):
     return hex_entropy(16)
Beispiel #47
0
 def generate_key(self):
     return hex_entropy(32)
Beispiel #48
0
 def get_auth_url(self, req):
     flow = self.flow
     state = hex_entropy()
     req.session[self.STATE_SKEY] = state
     flow.params['state'] = state
     return flow.step1_get_authorize_url()
Beispiel #49
0
 def test_hex_entropy(self):
     """hex_entropy() not affected by global random generator state"""
     random.seed(0)
     data = util.hex_entropy(64)
     random.seed(0)
     self.assertNotEqual(data, util.hex_entropy(64))
Beispiel #50
0
 def _generate_module_name(self):
     return 'tracmigratetest_' + hex_entropy(16)
Beispiel #51
0
    def _do_process(self, req):
        """Handle the redirect from the OpenID server.
        """
        oidconsumer, session = self._get_consumer(req)

        # Ask the library to check the response that the server sent
        # us.  Status is a code indicating the response type. info is
        # either None or a string containing more information about
        # the return type.
        info = oidconsumer.complete(req.args,req.args['openid.return_to'])

        css_class = 'error'
        if info.status == consumer.FAILURE and info.identity_url:
            # In the case of failure, if info is non-None, it is the
            # URL that we were verifying. We include it in the error
            # message to help the user figure out what happened.
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url),
                             info.message)
        elif info.status == consumer.SUCCESS:
            # Success means that the transaction completed without
            # error. If info is None, it means that the user cancelled
            # the verification.
            css_class = 'alert'

            # This is a successful verification attempt. If this
            # was a real application, we would do our login,
            # comment posting, etc. here.
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url),)
            remote_user = info.identity_url
            if info.endpoint.canonicalID:
                # You should authorize i-name users by their canonicalID,
                # rather than their more human-friendly identifiers.  That
                # way their account with you is not compromised if their
                # i-name registration expires and is bought by someone else.
                message += ("  This is an i-name, and its persistent ID is %s"
                            % (cgi.escape(info.endpoint.canonicalID),))
                remote_user = info.endpoint.canonicalID

            cookie = hex_entropy()
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                           "VALUES (%s, %s, %s, %s)", (cookie, remote_user,
                           self._get_masked_address(req.remote_addr), int(time.time())))
            db.commit()

            req.authname = info.identity_url
            req.outcookie['trac_auth'] = cookie
            req.outcookie['trac_auth']['path'] = req.href()
            req.outcookie['trac_auth']['expires'] = 60*60*24

            reg_info = sreg.SRegResponse.fromSuccessResponse(info).getExtensionArgs()

            if reg_info and reg_info.has_key('nickname') and len(reg_info['nickname']) > 0:
                req.session['name'] = reg_info['nickname']
            if reg_info and reg_info.has_key('email') and len(reg_info['email']) > 0:
                req.session['email'] = reg_info['email']

        elif info.status == consumer.CANCEL:
            # cancelled
            message = 'Verification cancelled'
        elif info.status == consumer.SETUP_NEEDED:
            if info.setup_url:
                message = '<a href=%s>Setup needed</a>' % (
                    quoteattr(info.setup_url),)
            else:
                # This means auth didn't succeed, but you're welcome to try
                # non-immediate mode.
                message = 'Setup needed'
        else:
            # Either we don't understand the code or there is no
            # openid_url included with the error. Give a generic
            # failure message. The library should supply debug
            # information in a log.
            message = 'Verification failed.'

        self._commit_session(session, req)

        add_stylesheet(req, 'authopenid/css/openid.css')
        return 'openidlogin.html', {
            'action': req.href.openidverify(),
            'message': message,
            'css_class': css_class
            }, None
Beispiel #52
0
    def _do_process(self, req):
        """Handle the redirect from the OpenID server.
        """
        db = self.env.get_db_cnx()
        oidconsumer, session = self._get_consumer(req, db)

        # Ask the library to check the response that the server sent
        # us.  Status is a code indicating the response type. info is
        # either None or a string containing more information about
        # the return type.
        info = oidconsumer.complete(req.args, req.args["openid.return_to"])

        css_class = "error"
        if info.status == consumer.FAILURE and info.identity_url:
            # In the case of failure, if info is non-None, it is the
            # URL that we were verifying. We include it in the error
            # message to help the user figure out what happened.
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url), info.message)
        elif info.status == consumer.SUCCESS:
            # Success means that the transaction completed without
            # error. If info is None, it means that the user cancelled
            # the verification.
            css_class = "alert"

            # This is a successful verification attempt. If this
            # was a real application, we would do our login,
            # comment posting, etc. here.
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url),)
            remote_user = info.identity_url

            reg_info = None

            ax_response = ax.FetchResponse.fromSuccessResponse(info)
            if ax_response:
                ax_data = ax_response.getExtensionArgs()
                email = ax_data.get("value.ext0.1", "")
                if email:
                    reg_info = {"email": email, "fullname": email.split("@", 1)[0].replace(".", " ").title()}

            if not reg_info:
                response = sreg.SRegResponse.fromSuccessResponse(info)
                if response:
                    reg_info = response.getExtensionArgs()

            if self.strip_protocol:
                remote_user = remote_user[remote_user.find("://") + 3 :]
            if self.strip_trailing_slash and remote_user[-1] == "/":
                remote_user = remote_user[:-1]
            if info.endpoint.canonicalID:
                # You should authorize i-name users by their canonicalID,
                # rather than their more human-friendly identifiers.  That
                # way their account with you is not compromised if their
                # i-name registration expires and is bought by someone else.
                message += "  This is an i-name, and its persistent ID is %s" % (cgi.escape(info.endpoint.canonicalID),)
                remote_user = info.endpoint.canonicalID

            allowed = True
            if self.re_white_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through white-list." % remote_user)
                allowed = False
                for item in self.re_white_list:
                    if not allowed and item.match(remote_user):
                        allowed = True
                        self.env.log.debug("User white-listed.")
            if allowed and self.re_black_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through black-list." % remote_user)
                for item in self.re_black_list:
                    if item.match(remote_user):
                        allowed = False
                        self.env.log.debug("User black-listed.")

            if allowed and self.check_list:
                params = {self.check_list_key: remote_user}
                if reg_info and reg_info.has_key("email") and len(reg_info["email"]) > 0:
                    params["email"] = reg_info["email"]
                url = self.check_list + "?" + urllib.urlencode(params)
                self.env.log.debug("OpenID check list URL: %s" % url)
                result = simplejson.load(urllib.urlopen(url))
                if not result[self.check_list_key]:
                    allowed = False
                elif self.check_list_username:
                    new_user = result[self.check_list_username]
                    if new_user:
                        remote_user = new_user

            if allowed:
                cookie = hex_entropy()

                req.outcookie["trac_auth"] = cookie
                req.outcookie["trac_auth"]["path"] = req.href()
                req.outcookie["trac_auth"]["expires"] = self.trac_auth_expires

                req.session[self.openid_session_identity_url_key] = info.identity_url

                if reg_info and reg_info.has_key("fullname") and len(reg_info["fullname"]) > 0:
                    req.session["name"] = reg_info["fullname"]
                if reg_info and reg_info.has_key("email") and len(reg_info["email"]) > 0:
                    req.session["email"] = reg_info["email"]

                self._commit_session(session, req)

                if self.combined_username and req.session["name"]:
                    remote_user = "******" % (req.session["name"], remote_user)
                else:
                    if req.session.has_key("name"):
                        remote_user = req.session["name"]

                    # Check if we generated a colliding remote_user and make the user unique
                    collisions = 0
                    cremote_user = remote_user
                    while True:
                        ds = DetachedSession(self.env, remote_user)
                        if not ds.last_visit:
                            # New session
                            break
                        if not ds.has_key(self.openid_session_identity_url_key):
                            # Old session, without the identity url set
                            # Save the identity url then (bascially adopt the session)
                            ds[self.openid_session_identity_url_key] = info.identity_url
                            ds.save()
                            break
                        if ds[self.openid_session_identity_url_key] == info.identity_url:
                            # No collision
                            break
                        # We got us a collision
                        # Make the thing unique
                        collisions += 1
                        remote_user = "******" % (cremote_user, collisions + 1)

                req.authname = remote_user

                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute(
                    "INSERT INTO auth_cookie (cookie,name,ipnr,time) " "VALUES (%s, %s, %s, %s)",
                    (cookie, remote_user, self._get_masked_address(req.remote_addr), int(time.time())),
                )
                db.commit()

                req.redirect(req.session.get("oid.referer") or self.env.abs_href())
            else:
                message = "You are not allowed here."
        elif info.status == consumer.CANCEL:
            # cancelled
            message = "Verification cancelled"
        elif info.status == consumer.SETUP_NEEDED:
            if info.setup_url:
                message = "<a href=%s>Setup needed</a>" % (quoteattr(info.setup_url),)
            else:
                # This means auth didn't succeed, but you're welcome to try
                # non-immediate mode.
                message = "Setup needed"
        else:
            # Either we don't understand the code or there is no
            # openid_url included with the error. Give a generic
            # failure message. The library should supply debug
            # information in a log.
            message = "Verification failed."

        self._commit_session(session, req)

        add_stylesheet(req, "authopenid/css/openid.css")
        add_script(req, "authopenid/js/openid-jquery.js")
        return (
            "openidlogin.html",
            {
                "images": req.href.chrome("authopenid/images") + "/",
                "action": req.href.openidverify(),
                "message": message,
                "signup": self.signup_link,
                "whatis": self.whatis_link,
                "css_class": css_class,
                "custom_provider_name": self.custom_provider_name,
                "custom_provider_label": self.custom_provider_label,
                "custom_provider_url": self.custom_provider_url,
                "custom_provider_image": self.custom_provider_image,
            },
            None,
        )
Beispiel #53
0
    def _do_process(self, req):
        """Handle the redirect from the OpenID server.
        """
        db = self.env.get_db_cnx()
        oidconsumer, oidsession = self._get_consumer(req, db)

        # Ask the library to check the response that the server sent
        # us.  Status is a code indicating the response type. info is
        # either None or a string containing more information about
        # the return type.
        current_url = req.abs_href(req.path_info)
        info = oidconsumer.complete(req.args,current_url)

        css_class = 'error'
        if info.status == consumer.FAILURE and info.identity_url:
            # In the case of failure, if info is non-None, it is the
            # URL that we were verifying. We include it in the error
            # message to help the user figure out what happened.
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url),
                             info.message)
        elif info.status == consumer.SUCCESS:
            # Success means that the transaction completed without
            # error. If info is None, it means that the user cancelled
            # the verification.
            css_class = 'alert'

            session_attr = {}           # attributes for new "user"

            # This is a successful verification attempt. If this
            # was a real application, we would do our login,
            # comment posting, etc. here.
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url),)
            remote_user = info.identity_url

            sreg_info = sreg.SRegResponse.fromSuccessResponse(info) or {}

            ax_response = ax.FetchResponse.fromSuccessResponse(info)
            ax_info = {}
            if ax_response:
                for alias, uri in self.openid_ax_attrs.items():
                    values = ax_response.data.get(uri,[])
                    if values:
                        ax_info[alias] = values[0]

            email = (ax_info.get('email')
                     or ax_info.get('email2')
                     or sreg_info.get('email'))

            fullname = (
                ' '.join(filter(None, map(ax_info.get,
                                          ('firstname', 'lastname'))))
                or sreg_info.get('fullname')
                or (email and email.split('@',1)[0].replace('.', ' ').title()))

            nickname = sreg_info.get('nickname')

            if self.groups_to_request and TeamsResponse:
                teams_response = TeamsResponse.fromSuccessResponse(info)
                if teams_response:
                    # be careful not to make user a member of any trac groups
                    # not named in groups_to_request
                    teams = set(teams_response.teams
                                ).intersection(self.groups_to_request)
                    if teams:
                        session_attr['openid.teams'] = ','.join(teams)

            if self.strip_protocol:
                remote_user = remote_user[remote_user.find('://')+3:]
            if self.strip_trailing_slash and remote_user[-1] == '/':
                remote_user = remote_user[:-1]
            if info.endpoint.canonicalID:
                # You should authorize i-name users by their canonicalID,
                # rather than their more human-friendly identifiers.  That
                # way their account with you is not compromised if their
                # i-name registration expires and is bought by someone else.
                message += ("  This is an i-name, and its persistent ID is %s"
                            % (cgi.escape(info.endpoint.canonicalID),))
                remote_user = info.endpoint.canonicalID

            allowed = True
            if self.re_white_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through white-list." % remote_user)
                allowed = False
                for item in self.re_white_list:
                    if not allowed and item.match(remote_user):
                        allowed = True
                        self.env.log.debug("User white-listed.")
            if allowed and self.re_black_list:
                self.env.log.debug("Filtering REMOTE_USER '%s' through black-list." % remote_user)
                for item in self.re_black_list:
                    if item.match(remote_user):
                        allowed = False
                        self.env.log.debug("User black-listed.")
            if allowed and self.re_email_white_list:
                self.env.log.debug("Filtering email %r through email white-list." % email)
                allowed = False
                if email:
                    for item in self.re_email_white_list:
                        if not allowed and item.match(email):
                            allowed = True
                            self.env.log.debug("User email white-listed.")

            if allowed and self.check_list:
                allowed = False
                params = {self.check_list_key: remote_user}
                if email:
                    params['email'] = email
                url = self.check_list + '?' + urllib.urlencode(params)
                self.env.log.debug('OpenID check list URL: %s' % url)
                try:
                    result = json.load(urllib.urlopen(url))
                    if result[self.check_list_key]:
                        if self.check_list_username:
                            cl_username = unicode(
                                result[self.check_list_username])
                            if not cl_username:
                                raise ValueError("Bad value for username")
                        allowed = True
                except Exception, ex:
                    self.env.log.error('OpenID check_list failed: %s' % ex)

            if allowed:
                cookie = hex_entropy()
                cookie_lifetime = self.trac_auth_cookie_lifetime

                req.outcookie['trac_auth'] = cookie
                req.outcookie['trac_auth']['path'] = req.href()
                if cookie_lifetime > 0:
                    req.outcookie['trac_auth']['expires'] = cookie_lifetime

                session_attr[self.openid_session_identity_url_key] = info.identity_url
                if email:
                    session_attr['email'] = email
                if fullname:
                    session_attr['name'] = fullname

                self._commit_oidsession(oidsession, req)

                # First look for an existing authenticated session with
                # matching identity_url.
                self.env.log.debug('Checking URL: %s' % info.identity_url)
                authname_for_identity_url = self.get_user(info.identity_url)
                if authname_for_identity_url:
                    authname = authname_for_identity_url
                    ds = DetachedSession(self.env, authname)
                    # The user already exists, update team membership
                    # XXX: Should also update name and/or email? (This would
                    # be an API change.)
                    for name in ['openid.teams']:
                        if name in session_attr:
                            ds[name] = session_attr[name]
                        elif name in ds:
                            del ds[name]
                    ds.save()
                else:
                    # New identity URL -> create new authname/user.
                    if self.check_list and self.check_list_username:
                        authname = cl_username
                    elif self.use_email_as_authname and email:
                        authname = email
                    elif self.use_nickname_as_authname and nickname:
                        authname = nickname
                    elif session_attr.get('name'):
                        authname = session_attr['name']
                        if self.combined_username:
                            authname = '%s <%s>' % (authname, remote_user)
                    else:
                        authname = remote_user

                    # Possibly lower-case the authname.
                    if self.lowercase_authname:
                        authname = authname.lower()

                    if self.trust_authname:
                        ds = DetachedSession(self.env, authname)
                    else:
                        # Make authname unique in case of collisions
                        def authnames(base):
                            yield base
                            for attempt in itertools.count(2):
                                yield "%s (%d)" % (base, attempt)

                        users_and_groups_with_permissions = set(
                            user
                            for user, perm
                            in PermissionSystem(self.env).get_all_permissions())

                        for authname in authnames(authname):
                            ds = DetachedSession(self.env, authname)
                            # At least in 0.12.2, this means no session exists.
                            no_session_exists = ds.last_visit == 0 and len(ds) == 0
                            no_permissions_defined = authname not in users_and_groups_with_permissions
                            if (no_session_exists and no_permissions_defined):
                                # name is free :-)
                                break

                    # Set attributes for new user on the
                    # current anonymous session.  It will be promoted to
                    # the new authenticated session on the next request
                    # (by Session.__init__).
                    #
                    # NB: avoid dict.update here to ensure that
                    # DetachedSession.__getitem__ gets a chance to
                    # normalize values
                    for name, value in session_attr.items():
                        req.session[name] = value
                    self.env.log.info("Created new user '%s' for "
                        "OpenID identifier %s", authname, info.identity_url)

                req.authname = authname

                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "
                               "VALUES (%s, %s, %s, %s)", (cookie, authname,
                               self._get_masked_address(req.remote_addr), int(time.time())))
                db.commit()

                req.redirect(req.session.get('oid.referer') or self.env.abs_href())
            else:
                message = 'You are not allowed here.'
Beispiel #54
0
 def _generate_module_name(self):
     return 'trac_convert_db_' + hex_entropy(16)
    def _get_name_for_cookie(self, req, cookie):
        """Returns the username for the current Trac session.

        It's called by authenticate() when the cookie 'trac_auth' is sent
        by the browser.
        """

        acctmgr = AccountManager(self.env)
        name = None
        # Replicate _get_name_for_cookie() or _cookie_to_name() since Trac 1.0
        # adding special handling of persistent sessions, as the user may have
        # a dynamic IP adress and this would lead to the user being logged out
        # due to an IP address conflict.
        if 'trac_auth_session' in req.incookie or True:
            with self.env.db_query as db:
                cursor = db.cursor()
                sql = "SELECT name FROM auth_cookie WHERE cookie=%s AND ipnr=%s"
                args = (cookie.value, req.remote_addr)
                if acctmgr.persistent_sessions or not self.check_ip:
                    sql = "SELECT name FROM auth_cookie WHERE cookie=%s"
                    args = (cookie.value,)
                cursor.execute(sql, args)
                name = cursor.fetchone()
            name = name and name[0] or None
        if name is None:
            self._expire_cookie(req)

        if acctmgr.persistent_sessions and name and \
                'trac_auth_session' in req.incookie and \
                int(req.incookie['trac_auth_session'].value) < \
                int(time.time()) - self.UPDATE_INTERVAL:
            # Persistent sessions enabled, the user is logged in
            # ('name' exists) and has actually decided to use this feature
            # (indicated by the 'trac_auth_session' cookie existing).
            #
            # NOTE: This method is called on every request.

            # Refresh session cookie
            # Update the timestamp of the session so that it doesn't expire.
            self.env.log.debug('Updating session %s for user %s' %
                                (cookie.value, name))
            # Refresh in database
            with self.env.db_transaction as db:
                cursor = db.cursor()
                cursor.execute("""
                    UPDATE  auth_cookie
                        SET time=%s
                    WHERE   cookie=%s
                    """, (int(time.time()), cookie.value))

            # Change session ID (cookie.value) now and then as it otherwise
            #   never would change at all (i.e. stay the same indefinitely and
            #   therefore is more vulnerable to be hacked).
            if random.random() + self.cookie_refresh_pct / 100.0 > 1:
                old_cookie = cookie.value
                # Update auth cookie value
                cookie.value = hex_entropy()
                self.env.log.debug('Changing session id for user %s to %s'
                                    % (name, cookie.value))
                with self.env.db_transaction:
                    cursor = db.cursor()
                    cursor.execute("""
                        UPDATE  auth_cookie
                            SET cookie=%s
                        WHERE   cookie=%s
                        """, (cookie.value, old_cookie))
                if self.auth_cookie_path:
                    self._distribute_auth(req, cookie.value, name)

            cookie_lifetime = self.cookie_lifetime
            cookie_path = self._get_cookie_path(req)
            req.outcookie['trac_auth'] = cookie.value
            req.outcookie['trac_auth']['path'] = cookie_path
            req.outcookie['trac_auth']['expires'] = cookie_lifetime
            req.outcookie['trac_auth_session'] = int(time.time())
            req.outcookie['trac_auth_session']['path'] = cookie_path
            req.outcookie['trac_auth_session']['expires'] = cookie_lifetime
            try:
                if self.env.secure_cookies:
                    req.outcookie['trac_auth']['secure'] = True
                    req.outcookie['trac_auth_session']['secure'] = True
            except AttributeError:
                # Report details about Trac compatibility for the feature.
                self.env.log.debug(
                    """Restricting cookies to HTTPS connections is requested,
                    but is supported only by Trac 0.11.2 or later version.
                    """)
        return name