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