Skip to content

Commit 72df2d6

Browse files
committed
Add tests for username_prefix options
Test that - username_prefix is actually prepended to user names when logging in via GitHub - HTTP login still works and yields unprefixed user names
1 parent 79b562c commit 72df2d6

File tree

1 file changed

+89
-13
lines changed

1 file changed

+89
-13
lines changed

runtests.py

Lines changed: 89 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import json
1616
import os
1717
import random
18+
import re
1819
import shutil
1920
import signal
2021
import subprocess
@@ -41,6 +42,7 @@
4142

4243
ENV = 'test-trac-github'
4344
CONF = '%s/conf/trac.ini' % ENV
45+
HTDIGEST = '%s/passwd' % ENV
4446
URL = 'http://localhost:8765/%s' % ENV
4547
SECRET = 'test-secret'
4648
HEADERS = {'Content-Type': 'application/json', 'X-GitHub-Event': 'push'}
@@ -148,6 +150,8 @@ def createTracEnvironment(cls, **kwargs):
148150
conf.set('github', 'access_token', kwargs['access_token'])
149151
if 'webhook_secret' in kwargs:
150152
conf.set('github', 'webhook_secret', kwargs['webhook_secret'])
153+
if 'username_prefix' in kwargs:
154+
conf.set('github', 'username_prefix', kwargs['username_prefix'])
151155

152156
if SHOW_LOG:
153157
# The [logging] section already exists in the default trac.ini file.
@@ -177,6 +181,10 @@ def createTracEnvironment(cls, **kwargs):
177181
with open(CONF, 'wb') as fp:
178182
conf.write(fp)
179183

184+
with open(HTDIGEST, 'w') as fp:
185+
# user: user, pass: pass, realm: realm
186+
fp.write("user:realm:8493fbc53ba582fb4c044c456bdc40eb\n")
187+
180188
run_resync = kwargs['resync'] if 'resync' in kwargs else True
181189
if run_resync:
182190
# Allow skipping resync for perfomance reasons if not required
@@ -200,7 +208,7 @@ def startTracd(cls, **kwargs):
200208
if SHOW_LOG:
201209
kwargs['stdout'] = sys.stdout
202210
kwargs['stderr'] = sys.stderr
203-
cls.tracd = subprocess.Popen(tracd + ['--port', '8765', ENV], **kwargs)
211+
cls.tracd = subprocess.Popen(tracd + ['--port', '8765', '--auth=*,%s,realm' % HTDIGEST, ENV], **kwargs)
204212

205213
while True:
206214
try:
@@ -538,14 +546,42 @@ def testLoginWithUnconfiguredClientId(self):
538546
"An unconfigured GitHubLogin module should redirect and print "
539547
"a warning on login attempts.")
540548

549+
def attemptHttpAuth(self, testenv, **kwargs):
550+
"""
551+
Helper method that attempts to log in using HTTP authentication in the
552+
given testenv; returns a tuple where the first item is the error
553+
message in the notification box on the trac page loaded after the login
554+
attempt (or an empty string on success) and the second item is the
555+
username as seen by trac.
556+
"""
557+
with TracContext(self, env=testenv, resync=False, **kwargs):
558+
session = requests.Session()
559+
560+
# This logs into trac using HTTP authentication
561+
# This adds a oauth_state parameter in the Trac session.
562+
response = session.get(URL + '/login', auth=requests.auth.HTTPDigestAuth('user', 'pass'))
563+
self.assertNotEqual(response.status_code, 403)
564+
565+
response = session.get(URL + '/newticket') # this should trigger IPermissionGroupProvider
566+
self.assertEqual(response.status_code, 200)
567+
tree = html.fromstring(response.content)
568+
warning = ''.join(tree.xpath('//div[@id="warning"]/text()')).strip()
569+
user = ''
570+
match = re.match(r"logged in as (.*)",
571+
', '.join(tree.xpath('//div[@id="metanav"]/ul/li[@class="first"]/text()')))
572+
if match:
573+
user = match.group(1)
574+
return (warning, user)
575+
541576
def attemptValidOauth(self, testenv, callback, **kwargs):
542577
"""
543578
Helper method that runs a valid OAuth2 attempt in the given testenv
544579
with the given callback; returns a tuple where the first item is the
545580
error message in the notification box on the trac page loaded after the
546-
login attempt (or an empty string on success) and the second item is
581+
login attempt (or an empty string on success), the second item is
547582
a list of email addresses found in email fields of the preferences
548-
after login.
583+
after login and the third item is the username of the user that was
584+
logged in as seen by trac..
549585
"""
550586
ctxt_kwargs = {}
551587
other_kwargs = {}
@@ -579,8 +615,14 @@ def attemptValidOauth(self, testenv, callback, **kwargs):
579615
response = session.get(URL + '/prefs')
580616
self.assertEqual(response.status_code, 200)
581617
tree = html.fromstring(response.content)
582-
return (''.join(tree.xpath('//div[@id="warning"]/text()')).strip(),
583-
tree.xpath('//input[@id="email"]/@value'))
618+
warning = ''.join(tree.xpath('//div[@id="warning"]/text()')).strip()
619+
email = tree.xpath('//input[@id="email"]/@value')
620+
user = ''
621+
match = re.match(r"logged in as (.*)",
622+
', '.join(tree.xpath('//div[@id="metanav"]/ul/li[@class="first"]/text()')))
623+
if match:
624+
user = match.group(1)
625+
return (warning, email, user)
584626
finally:
585627
# disable callback again
586628
updateMockData(self.mockdata, postcallback="")
@@ -590,7 +632,7 @@ def testOauthBackendUnavailable(self):
590632
Test that an OAuth backend that resets the connection does not crash
591633
the login
592634
"""
593-
errmsg, emails = self.attemptValidOauth(self.trac_env_broken, "")
635+
errmsg, emails, _ = self.attemptValidOauth(self.trac_env_broken, "")
594636
self.assertIn(
595637
"Invalid request. Please try to login again.",
596638
errmsg,
@@ -600,7 +642,7 @@ def testOauthBackendFails(self):
600642
"""Test that an OAuth backend that fails does not crash the login"""
601643
def cb(path, args):
602644
return 403, {}
603-
errmsg, emails = self.attemptValidOauth(self.trac_env, cb)
645+
errmsg, emails, _ = self.attemptValidOauth(self.trac_env, cb)
604646
self.assertIn(
605647
"Invalid request. Please try to login again.",
606648
errmsg,
@@ -621,7 +663,7 @@ def testOauthValidButUnavailAPI(self):
621663
Test that accessing an unavailable GitHub API with what seems to be
622664
a valid OAuth2 token does not crash the login
623665
"""
624-
errmsg, emails = self.attemptValidOauth(self.trac_env_broken_api, self.oauthCallbackSuccess)
666+
errmsg, emails, _ = self.attemptValidOauth(self.trac_env_broken_api, self.oauthCallbackSuccess)
625667
self.assertIn(
626668
"An error occurred while communicating with the GitHub API",
627669
errmsg,
@@ -632,9 +674,9 @@ def testOauthValidButBrokenAPI(self):
632674
Test that accessing an broken GitHub API with what seems to be a valid
633675
OAuth2 token does not crash the login
634676
"""
635-
errmsg, emails = self.attemptValidOauth(self.trac_env_broken_api,
636-
self.oauthCallbackSuccess,
637-
retcode=403)
677+
errmsg, emails, _ = self.attemptValidOauth(self.trac_env_broken_api,
678+
self.oauthCallbackSuccess,
679+
retcode=403)
638680
self.assertIn(
639681
"An error occurred while communicating with the GitHub API",
640682
errmsg,
@@ -656,7 +698,7 @@ def testOauthValidEmailAPIInvalid(self):
656698
}
657699
}
658700

659-
errmsg, emails = self.attemptValidOauth(
701+
errmsg, emails, _ = self.attemptValidOauth(
660702
self.trac_env, self.oauthCallbackSuccess, retcode=200,
661703
answers=answers, request_email=True)
662704
self.assertIn(
@@ -666,14 +708,24 @@ def testOauthValidEmailAPIInvalid(self):
666708

667709
def getEmail(self, answers, **kwargs):
668710
"""Get and return the email address the system has chosen for the given config and answers"""
669-
errmsg, emails = self.attemptValidOauth(
711+
errmsg, emails, _ = self.attemptValidOauth(
670712
self.trac_env, self.oauthCallbackSuccess, retcode=200,
671713
answers=answers, **kwargs)
672714
self.assertEqual(len(errmsg), 0,
673715
"Successful login should not print an error.")
674716

675717
return emails
676718

719+
def getUser(self, answers, **kwargs):
720+
"""Get and return the user name the system has chosen for the given config and answers"""
721+
errmsg, _, user = self.attemptValidOauth(
722+
self.trac_env, self.oauthCallbackSuccess, retcode=200,
723+
answers=answers, **kwargs)
724+
self.assertEqual(len(errmsg), 0,
725+
"Successful login should not print an error.")
726+
727+
return user
728+
677729
def testOauthValid(self):
678730
"""Test that a login with a valid OAuth2 token succeeds"""
679731
answers = {
@@ -686,6 +738,27 @@ def testOauthValid(self):
686738

687739
email = self.getEmail(answers)
688740
self.assertEqual(email, ['[email protected]'])
741+
user = self.getUser(answers)
742+
self.assertEqual(user, 'trololol')
743+
744+
def testUsernamePrefix(self):
745+
"""Test that setting a prefix for GitHub usernames works"""
746+
answers = {
747+
'/user': {
748+
'user': 'trololol',
749+
'email': '[email protected]',
750+
'login': 'trololol'
751+
}
752+
}
753+
754+
user = self.getUser(answers, username_prefix='github-')
755+
self.assertEqual(user, 'github-trololol')
756+
757+
errmsg, user = self.attemptHttpAuth(self.trac_env, username_prefix='github-')
758+
self.assertEqual(len(errmsg), 0,
759+
"HTTP authentication should still work.")
760+
self.assertEqual(user, "user",
761+
"Non-GitHub-authentication should yield unprefixed usernames")
689762

690763
def testOauthEmailIgnoresUnverified(self):
691764
"""
@@ -1163,6 +1236,7 @@ class TracContext(object):
11631236
'username',
11641237
'access_token',
11651238
'webhook_secret',
1239+
'username_prefix',
11661240
'resync')
11671241
""" List of all valid attributes to be passed to createTracEnvironment() """
11681242

@@ -1195,6 +1269,8 @@ def __init__(self, testobj, env=None, **kwargs):
11951269
group syncing. Defaults to unset.
11961270
:param webhook_secret: Secret used to validate WebHook API calls if
11971271
present. Defaults to unset.
1272+
:param username_prefix: Prefix for GitHub usernames to allow
1273+
co-existance of non-GitHub with GitHub accounts.
11981274
:param resync: `False` to skip running `trac admin repository resync`
11991275
during environment setup for speed reasons. Defaults to
12001276
`True`.

0 commit comments

Comments
 (0)