forked from buildbot/buildbot
-
Notifications
You must be signed in to change notification settings - Fork 6
/
auth.py
92 lines (75 loc) · 2.85 KB
/
auth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import os
from zope.interface import Interface, implements
from buildbot.status.web.base import HtmlResource
class IAuth(Interface):
"""Represent an authentication method."""
def authenticate(self, user, passwd):
"""Check whether C{user} / C{passwd} are valid."""
def errmsg(self):
"""Get the reason authentication failed."""
class AuthBase:
err = ""
def errmsg(self):
return self.err
class BasicAuth(AuthBase):
implements(IAuth)
"""Implement basic authentication against a list of user/passwd."""
userpass = []
"""List of user/pass tuples."""
def __init__(self, userpass):
"""C{userpass} is a list of (user, passwd)."""
for item in userpass:
assert isinstance(item, tuple)
u, p = item
assert isinstance(u, str)
assert isinstance(p, str)
self.userpass = userpass
def authenticate(self, user, passwd):
"""Check that C{user}/C{passwd} is a valid user/pass tuple."""
if not self.userpass:
self.err = "Bad self.userpass data"
return False
for u, p in self.userpass:
if user == u and passwd == p:
self.err = ""
return True
self.err = "Invalid username or password"
return False
class HTPasswdAuth(AuthBase):
implements(IAuth)
"""Implement authentication against an .htpasswd file."""
file = ""
"""Path to the .htpasswd file to use."""
def __init__(self, file):
"""C{file} is a path to an .htpasswd file."""
assert os.path.exists(file)
self.file = file
def authenticate(self, user, passwd):
"""Authenticate C{user} and C{passwd} against an .htpasswd file"""
if not os.path.exists(self.file):
self.err = "No such file: " + self.file
return False
# Fetch each line from the .htpasswd file and split it into a
# [user, passwd] array.
lines = [l.rstrip().split(':', 1)
for l in file(self.file).readlines()]
# Keep only the line for this login
lines = [l for l in lines if l[0] == user]
if not lines:
self.err = "Invalid user/passwd"
return False
# This is the DES-hash of the password. The first two characters are
# the salt used to introduce disorder in the DES algorithm.
hash = lines[0][1]
from crypt import crypt #@UnresolvedImport
res = hash == crypt(passwd, hash[0:2])
if res:
self.err = ""
else:
self.err = "Invalid user/passwd"
return res
class AuthFailResource(HtmlResource):
title = "Authentication Failed"
def content(self, request, cxt):
template = request.site.buildbot_service.templates.get_template("authfail.html")
return template.render(**cxt)