We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Authentication problem Buildbot 0.9.14
I created the class below
```
class MyAuth(CustomAuth):
    def check_credentials(user, password):
        if user == 'snow' and password == 'white':
            return True
        else:
            return False
```
and set it as my auth class.
```
c['www']['auth']=MyAuth()
```
But it throws following exception.
```
web.Server Traceback (most recent call last):
exceptions.AttributeError: 'str' object has no attribute 'providedBy'
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/server.py:195 in process
194                    self._encoder = encoder
195            self.render(resrc)
196        except:
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/server.py:255 in render
254        try:
255            body = resrc.render(self)
256        except UnsupportedMethod as e:
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:138 in render
137        """
138        return self._authorizedResource(request).render(request)
139
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:116 in _authorizedResource
115        if not authheader:
116            return util.DeferredResource(self._login(Anonymous()))
117
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:162 in _login
161        """
162        d = self._portal.login(credentials, None, IResource)
163        d.addCallbacks(self._loginSucceeded, self._loginFailed)
/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/cred/portal.py:118 in login
117        for i in self.checkers:
118            if i.providedBy(credentials):
119                return maybeDeferred(self.checkers[i].requestAvatarId, credentials
exceptions.AttributeError: 'str' object has no attribute 'providedBy'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `master/buildbot/www/auth.py`
Content:
```
1 # This file is part of Buildbot.  Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15 
16 from __future__ import absolute_import
17 from __future__ import print_function
18 
19 import re
20 from abc import ABCMeta
21 from abc import abstractmethod
22 
23 from twisted.cred.checkers import FilePasswordDB
24 from twisted.cred.checkers import ICredentialsChecker
25 from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse
26 from twisted.cred.credentials import IUsernamePassword
27 from twisted.cred.error import UnauthorizedLogin
28 from twisted.cred.portal import IRealm
29 from twisted.cred.portal import Portal
30 from twisted.internet import defer
31 from twisted.web.error import Error
32 from twisted.web.guard import BasicCredentialFactory
33 from twisted.web.guard import DigestCredentialFactory
34 from twisted.web.guard import HTTPAuthSessionWrapper
35 from twisted.web.resource import IResource
36 from zope.interface import implementer
37 
38 from buildbot.util import bytes2unicode
39 from buildbot.util import config
40 from buildbot.util import unicode2bytes
41 from buildbot.www import resource
42 
43 
44 class AuthRootResource(resource.Resource):
45 
46     def getChild(self, path, request):
47         # return dynamically generated resources
48         if path == b'login':
49             return self.master.www.auth.getLoginResource()
50         elif path == b'logout':
51             return self.master.www.auth.getLogoutResource()
52         return resource.Resource.getChild(self, path, request)
53 
54 
55 class AuthBase(config.ConfiguredMixin):
56 
57     def __init__(self, userInfoProvider=None):
58         self.userInfoProvider = userInfoProvider
59 
60     def reconfigAuth(self, master, new_config):
61         self.master = master
62 
63     def maybeAutoLogin(self, request):
64         return defer.succeed(None)
65 
66     def getLoginResource(self):
67         raise Error(501, b"not implemented")
68 
69     def getLogoutResource(self):
70         return LogoutResource(self.master)
71 
72     @defer.inlineCallbacks
73     def updateUserInfo(self, request):
74         session = request.getSession()
75         if self.userInfoProvider is not None:
76             infos = yield self.userInfoProvider.getUserInfo(session.user_info['username'])
77             session.user_info.update(infos)
78             session.updateSession(request)
79 
80     def getConfigDict(self):
81         return {'name': type(self).__name__}
82 
83 
84 class UserInfoProviderBase(config.ConfiguredMixin):
85     name = "noinfo"
86 
87     def getUserInfo(self, username):
88         return defer.succeed({'email': username})
89 
90 
91 class LoginResource(resource.Resource):
92 
93     def render_GET(self, request):
94         return self.asyncRenderHelper(request, self.renderLogin)
95 
96     @defer.inlineCallbacks
97     def renderLogin(self, request):
98         raise NotImplementedError
99 
100 
101 class NoAuth(AuthBase):
102     pass
103 
104 
105 class RemoteUserAuth(AuthBase):
106     header = b"REMOTE_USER"
107     headerRegex = re.compile(br"(?P<username>[^ @]+)@(?P<realm>[^ @]+)")
108 
109     def __init__(self, header=None, headerRegex=None, **kwargs):
110         AuthBase.__init__(self, **kwargs)
111         if self.userInfoProvider is None:
112             self.userInfoProvider = UserInfoProviderBase()
113         if header is not None:
114             self.header = header
115         if headerRegex is not None:
116             self.headerRegex = re.compile(headerRegex)
117 
118     @defer.inlineCallbacks
119     def maybeAutoLogin(self, request):
120         header = request.getHeader(self.header)
121         if header is None:
122             raise Error(403, b"missing http header " + self.header + b". Check your reverse proxy config!")
123         res = self.headerRegex.match(header)
124         if res is None:
125             raise Error(
126                 403, b'http header does not match regex! "' + header + b'" not matching ' + self.headerRegex.pattern)
127         session = request.getSession()
128         if session.user_info != dict(res.groupdict()):
129             session.user_info = dict(res.groupdict())
130             yield self.updateUserInfo(request)
131 
132 
133 @implementer(IRealm)
134 class AuthRealm(object):
135 
136     def __init__(self, master, auth):
137         self.auth = auth
138         self.master = master
139 
140     def requestAvatar(self, avatarId, mind, *interfaces):
141         if IResource in interfaces:
142             return (IResource,
143                     PreAuthenticatedLoginResource(self.master, avatarId),
144                     lambda: None)
145         raise NotImplementedError()
146 
147 
148 class TwistedICredAuthBase(AuthBase):
149 
150     def __init__(self, credentialFactories, checkers, **kwargs):
151         AuthBase.__init__(self, **kwargs)
152         if self.userInfoProvider is None:
153             self.userInfoProvider = UserInfoProviderBase()
154         self.credentialFactories = credentialFactories
155         self.checkers = checkers
156 
157     def getLoginResource(self):
158         return HTTPAuthSessionWrapper(
159             Portal(AuthRealm(self.master, self), self.checkers),
160             self.credentialFactories)
161 
162 
163 class HTPasswdAuth(TwistedICredAuthBase):
164 
165     def __init__(self, passwdFile, **kwargs):
166         TwistedICredAuthBase.__init__(
167             self,
168             [DigestCredentialFactory(b"md5", b"buildbot"),
169              BasicCredentialFactory(b"buildbot")],
170             [FilePasswordDB(passwdFile)],
171             **kwargs)
172 
173 
174 class UserPasswordAuth(TwistedICredAuthBase):
175 
176     def __init__(self, users, **kwargs):
177         if isinstance(users, dict):
178             users = {user: unicode2bytes(pw) for user, pw in users.items()}
179         elif isinstance(users, list):
180             users = [(user, unicode2bytes(pw)) for user, pw in users]
181         TwistedICredAuthBase.__init__(
182             self,
183             [DigestCredentialFactory(b"md5", b"buildbot"),
184              BasicCredentialFactory(b"buildbot")],
185             [InMemoryUsernamePasswordDatabaseDontUse(**dict(users))],
186             **kwargs)
187 
188 
189 @implementer(ICredentialsChecker)
190 class CustomAuth(TwistedICredAuthBase):
191     __metaclass__ = ABCMeta
192     credentialInterfaces = IUsernamePassword
193 
194     def __init__(self, **kwargs):
195         TwistedICredAuthBase.__init__(
196             self,
197             [BasicCredentialFactory(b"buildbot")],
198             [self],
199             **kwargs)
200 
201     def requestAvatarId(self, cred):
202         if self.check_credentials(cred.username, cred.password):
203             return defer.succeed(cred.username)
204         return defer.fail(UnauthorizedLogin())
205 
206     @abstractmethod
207     def check_credentials(username, password):
208         return False
209 
210 
211 def _redirect(master, request):
212     url = request.args.get(b"redirect", [b"/"])[0]
213     url = bytes2unicode(url)
214     return resource.Redirect(master.config.buildbotURL + "#" + url)
215 
216 
217 class PreAuthenticatedLoginResource(LoginResource):
218     # a LoginResource which is already authenticated via a
219     # HTTPAuthSessionWrapper
220 
221     def __init__(self, master, username):
222         LoginResource.__init__(self, master)
223         self.username = username
224 
225     @defer.inlineCallbacks
226     def renderLogin(self, request):
227         session = request.getSession()
228         session.user_info = dict(username=bytes2unicode(self.username))
229         yield self.master.www.auth.updateUserInfo(request)
230         raise _redirect(self.master, request)
231 
232 
233 class LogoutResource(resource.Resource):
234 
235     def render_GET(self, request):
236         session = request.getSession()
237         session.expire()
238         session.updateSession(request)
239         request.redirect(_redirect(self.master, request).url)
240         return b''
241
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/master/buildbot/www/auth.py b/master/buildbot/www/auth.py
--- a/master/buildbot/www/auth.py
+++ b/master/buildbot/www/auth.py
@@ -189,7 +189,7 @@
 @implementer(ICredentialsChecker)
 class CustomAuth(TwistedICredAuthBase):
     __metaclass__ = ABCMeta
-    credentialInterfaces = IUsernamePassword
+    credentialInterfaces = [IUsernamePassword]
 
     def __init__(self, **kwargs):
         TwistedICredAuthBase.__init__(

{"golden_diff": "diff --git a/master/buildbot/www/auth.py b/master/buildbot/www/auth.py\n--- a/master/buildbot/www/auth.py\n+++ b/master/buildbot/www/auth.py\n@@ -189,7 +189,7 @@\n @implementer(ICredentialsChecker)\n class CustomAuth(TwistedICredAuthBase):\n     __metaclass__ = ABCMeta\n-    credentialInterfaces = IUsernamePassword\n+    credentialInterfaces = [IUsernamePassword]\n \n     def __init__(self, **kwargs):\n         TwistedICredAuthBase.__init__(\n", "issue": "Authentication problem Buildbot 0.9.14\nI created the class below\r\n```\r\nclass MyAuth(CustomAuth):\r\n    def check_credentials(user, password):\r\n        if user == 'snow' and password == 'white':\r\n            return True\r\n        else:\r\n            return False\r\n```\r\nand set it as my auth class.\r\n```\r\nc['www']['auth']=MyAuth()\r\n```\r\nBut it throws following exception.\r\n```\r\nweb.Server Traceback (most recent call last):\r\nexceptions.AttributeError: 'str' object has no attribute 'providedBy'\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/server.py:195 in process\r\n194                    self._encoder = encoder\r\n195            self.render(resrc)\r\n196        except:\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/server.py:255 in render\r\n254        try:\r\n255            body = resrc.render(self)\r\n256        except UnsupportedMethod as e:\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:138 in render\r\n137        \"\"\"\r\n138        return self._authorizedResource(request).render(request)\r\n139\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:116 in _authorizedResource\r\n115        if not authheader:\r\n116            return util.DeferredResource(self._login(Anonymous()))\r\n117\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/web/_auth/wrapper.py:162 in _login\r\n161        \"\"\"\r\n162        d = self._portal.login(credentials, None, IResource)\r\n163        d.addCallbacks(self._loginSucceeded, self._loginFailed)\r\n/home/buildbot/virtualenv.buildbot/local/lib/python2.7/site-packages/twisted/cred/portal.py:118 in login\r\n117        for i in self.checkers:\r\n118            if i.providedBy(credentials):\r\n119                return maybeDeferred(self.checkers[i].requestAvatarId, credentials\r\nexceptions.AttributeError: 'str' object has no attribute 'providedBy'\r\n```\n", "before_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\nfrom __future__ import absolute_import\nfrom __future__ import print_function\n\nimport re\nfrom abc import ABCMeta\nfrom abc import abstractmethod\n\nfrom twisted.cred.checkers import FilePasswordDB\nfrom twisted.cred.checkers import ICredentialsChecker\nfrom twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse\nfrom twisted.cred.credentials import IUsernamePassword\nfrom twisted.cred.error import UnauthorizedLogin\nfrom twisted.cred.portal import IRealm\nfrom twisted.cred.portal import Portal\nfrom twisted.internet import defer\nfrom twisted.web.error import Error\nfrom twisted.web.guard import BasicCredentialFactory\nfrom twisted.web.guard import DigestCredentialFactory\nfrom twisted.web.guard import HTTPAuthSessionWrapper\nfrom twisted.web.resource import IResource\nfrom zope.interface import implementer\n\nfrom buildbot.util import bytes2unicode\nfrom buildbot.util import config\nfrom buildbot.util import unicode2bytes\nfrom buildbot.www import resource\n\n\nclass AuthRootResource(resource.Resource):\n\n    def getChild(self, path, request):\n        # return dynamically generated resources\n        if path == b'login':\n            return self.master.www.auth.getLoginResource()\n        elif path == b'logout':\n            return self.master.www.auth.getLogoutResource()\n        return resource.Resource.getChild(self, path, request)\n\n\nclass AuthBase(config.ConfiguredMixin):\n\n    def __init__(self, userInfoProvider=None):\n        self.userInfoProvider = userInfoProvider\n\n    def reconfigAuth(self, master, new_config):\n        self.master = master\n\n    def maybeAutoLogin(self, request):\n        return defer.succeed(None)\n\n    def getLoginResource(self):\n        raise Error(501, b\"not implemented\")\n\n    def getLogoutResource(self):\n        return LogoutResource(self.master)\n\n    @defer.inlineCallbacks\n    def updateUserInfo(self, request):\n        session = request.getSession()\n        if self.userInfoProvider is not None:\n            infos = yield self.userInfoProvider.getUserInfo(session.user_info['username'])\n            session.user_info.update(infos)\n            session.updateSession(request)\n\n    def getConfigDict(self):\n        return {'name': type(self).__name__}\n\n\nclass UserInfoProviderBase(config.ConfiguredMixin):\n    name = \"noinfo\"\n\n    def getUserInfo(self, username):\n        return defer.succeed({'email': username})\n\n\nclass LoginResource(resource.Resource):\n\n    def render_GET(self, request):\n        return self.asyncRenderHelper(request, self.renderLogin)\n\n    @defer.inlineCallbacks\n    def renderLogin(self, request):\n        raise NotImplementedError\n\n\nclass NoAuth(AuthBase):\n    pass\n\n\nclass RemoteUserAuth(AuthBase):\n    header = b\"REMOTE_USER\"\n    headerRegex = re.compile(br\"(?P<username>[^ @]+)@(?P<realm>[^ @]+)\")\n\n    def __init__(self, header=None, headerRegex=None, **kwargs):\n        AuthBase.__init__(self, **kwargs)\n        if self.userInfoProvider is None:\n            self.userInfoProvider = UserInfoProviderBase()\n        if header is not None:\n            self.header = header\n        if headerRegex is not None:\n            self.headerRegex = re.compile(headerRegex)\n\n    @defer.inlineCallbacks\n    def maybeAutoLogin(self, request):\n        header = request.getHeader(self.header)\n        if header is None:\n            raise Error(403, b\"missing http header \" + self.header + b\". Check your reverse proxy config!\")\n        res = self.headerRegex.match(header)\n        if res is None:\n            raise Error(\n                403, b'http header does not match regex! \"' + header + b'\" not matching ' + self.headerRegex.pattern)\n        session = request.getSession()\n        if session.user_info != dict(res.groupdict()):\n            session.user_info = dict(res.groupdict())\n            yield self.updateUserInfo(request)\n\n\n@implementer(IRealm)\nclass AuthRealm(object):\n\n    def __init__(self, master, auth):\n        self.auth = auth\n        self.master = master\n\n    def requestAvatar(self, avatarId, mind, *interfaces):\n        if IResource in interfaces:\n            return (IResource,\n                    PreAuthenticatedLoginResource(self.master, avatarId),\n                    lambda: None)\n        raise NotImplementedError()\n\n\nclass TwistedICredAuthBase(AuthBase):\n\n    def __init__(self, credentialFactories, checkers, **kwargs):\n        AuthBase.__init__(self, **kwargs)\n        if self.userInfoProvider is None:\n            self.userInfoProvider = UserInfoProviderBase()\n        self.credentialFactories = credentialFactories\n        self.checkers = checkers\n\n    def getLoginResource(self):\n        return HTTPAuthSessionWrapper(\n            Portal(AuthRealm(self.master, self), self.checkers),\n            self.credentialFactories)\n\n\nclass HTPasswdAuth(TwistedICredAuthBase):\n\n    def __init__(self, passwdFile, **kwargs):\n        TwistedICredAuthBase.__init__(\n            self,\n            [DigestCredentialFactory(b\"md5\", b\"buildbot\"),\n             BasicCredentialFactory(b\"buildbot\")],\n            [FilePasswordDB(passwdFile)],\n            **kwargs)\n\n\nclass UserPasswordAuth(TwistedICredAuthBase):\n\n    def __init__(self, users, **kwargs):\n        if isinstance(users, dict):\n            users = {user: unicode2bytes(pw) for user, pw in users.items()}\n        elif isinstance(users, list):\n            users = [(user, unicode2bytes(pw)) for user, pw in users]\n        TwistedICredAuthBase.__init__(\n            self,\n            [DigestCredentialFactory(b\"md5\", b\"buildbot\"),\n             BasicCredentialFactory(b\"buildbot\")],\n            [InMemoryUsernamePasswordDatabaseDontUse(**dict(users))],\n            **kwargs)\n\n\n@implementer(ICredentialsChecker)\nclass CustomAuth(TwistedICredAuthBase):\n    __metaclass__ = ABCMeta\n    credentialInterfaces = IUsernamePassword\n\n    def __init__(self, **kwargs):\n        TwistedICredAuthBase.__init__(\n            self,\n            [BasicCredentialFactory(b\"buildbot\")],\n            [self],\n            **kwargs)\n\n    def requestAvatarId(self, cred):\n        if self.check_credentials(cred.username, cred.password):\n            return defer.succeed(cred.username)\n        return defer.fail(UnauthorizedLogin())\n\n    @abstractmethod\n    def check_credentials(username, password):\n        return False\n\n\ndef _redirect(master, request):\n    url = request.args.get(b\"redirect\", [b\"/\"])[0]\n    url = bytes2unicode(url)\n    return resource.Redirect(master.config.buildbotURL + \"#\" + url)\n\n\nclass PreAuthenticatedLoginResource(LoginResource):\n    # a LoginResource which is already authenticated via a\n    # HTTPAuthSessionWrapper\n\n    def __init__(self, master, username):\n        LoginResource.__init__(self, master)\n        self.username = username\n\n    @defer.inlineCallbacks\n    def renderLogin(self, request):\n        session = request.getSession()\n        session.user_info = dict(username=bytes2unicode(self.username))\n        yield self.master.www.auth.updateUserInfo(request)\n        raise _redirect(self.master, request)\n\n\nclass LogoutResource(resource.Resource):\n\n    def render_GET(self, request):\n        session = request.getSession()\n        session.expire()\n        session.updateSession(request)\n        request.redirect(_redirect(self.master, request).url)\n        return b''\n", "path": "master/buildbot/www/auth.py"}], "after_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\nfrom __future__ import absolute_import\nfrom __future__ import print_function\n\nimport re\nfrom abc import ABCMeta\nfrom abc import abstractmethod\n\nfrom twisted.cred.checkers import FilePasswordDB\nfrom twisted.cred.checkers import ICredentialsChecker\nfrom twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse\nfrom twisted.cred.credentials import IUsernamePassword\nfrom twisted.cred.error import UnauthorizedLogin\nfrom twisted.cred.portal import IRealm\nfrom twisted.cred.portal import Portal\nfrom twisted.internet import defer\nfrom twisted.web.error import Error\nfrom twisted.web.guard import BasicCredentialFactory\nfrom twisted.web.guard import DigestCredentialFactory\nfrom twisted.web.guard import HTTPAuthSessionWrapper\nfrom twisted.web.resource import IResource\nfrom zope.interface import implementer\n\nfrom buildbot.util import bytes2unicode\nfrom buildbot.util import config\nfrom buildbot.util import unicode2bytes\nfrom buildbot.www import resource\n\n\nclass AuthRootResource(resource.Resource):\n\n    def getChild(self, path, request):\n        # return dynamically generated resources\n        if path == b'login':\n            return self.master.www.auth.getLoginResource()\n        elif path == b'logout':\n            return self.master.www.auth.getLogoutResource()\n        return resource.Resource.getChild(self, path, request)\n\n\nclass AuthBase(config.ConfiguredMixin):\n\n    def __init__(self, userInfoProvider=None):\n        self.userInfoProvider = userInfoProvider\n\n    def reconfigAuth(self, master, new_config):\n        self.master = master\n\n    def maybeAutoLogin(self, request):\n        return defer.succeed(None)\n\n    def getLoginResource(self):\n        raise Error(501, b\"not implemented\")\n\n    def getLogoutResource(self):\n        return LogoutResource(self.master)\n\n    @defer.inlineCallbacks\n    def updateUserInfo(self, request):\n        session = request.getSession()\n        if self.userInfoProvider is not None:\n            infos = yield self.userInfoProvider.getUserInfo(session.user_info['username'])\n            session.user_info.update(infos)\n            session.updateSession(request)\n\n    def getConfigDict(self):\n        return {'name': type(self).__name__}\n\n\nclass UserInfoProviderBase(config.ConfiguredMixin):\n    name = \"noinfo\"\n\n    def getUserInfo(self, username):\n        return defer.succeed({'email': username})\n\n\nclass LoginResource(resource.Resource):\n\n    def render_GET(self, request):\n        return self.asyncRenderHelper(request, self.renderLogin)\n\n    @defer.inlineCallbacks\n    def renderLogin(self, request):\n        raise NotImplementedError\n\n\nclass NoAuth(AuthBase):\n    pass\n\n\nclass RemoteUserAuth(AuthBase):\n    header = b\"REMOTE_USER\"\n    headerRegex = re.compile(br\"(?P<username>[^ @]+)@(?P<realm>[^ @]+)\")\n\n    def __init__(self, header=None, headerRegex=None, **kwargs):\n        AuthBase.__init__(self, **kwargs)\n        if self.userInfoProvider is None:\n            self.userInfoProvider = UserInfoProviderBase()\n        if header is not None:\n            self.header = header\n        if headerRegex is not None:\n            self.headerRegex = re.compile(headerRegex)\n\n    @defer.inlineCallbacks\n    def maybeAutoLogin(self, request):\n        header = request.getHeader(self.header)\n        if header is None:\n            raise Error(403, b\"missing http header \" + self.header + b\". Check your reverse proxy config!\")\n        res = self.headerRegex.match(header)\n        if res is None:\n            raise Error(\n                403, b'http header does not match regex! \"' + header + b'\" not matching ' + self.headerRegex.pattern)\n        session = request.getSession()\n        if session.user_info != dict(res.groupdict()):\n            session.user_info = dict(res.groupdict())\n            yield self.updateUserInfo(request)\n\n\n@implementer(IRealm)\nclass AuthRealm(object):\n\n    def __init__(self, master, auth):\n        self.auth = auth\n        self.master = master\n\n    def requestAvatar(self, avatarId, mind, *interfaces):\n        if IResource in interfaces:\n            return (IResource,\n                    PreAuthenticatedLoginResource(self.master, avatarId),\n                    lambda: None)\n        raise NotImplementedError()\n\n\nclass TwistedICredAuthBase(AuthBase):\n\n    def __init__(self, credentialFactories, checkers, **kwargs):\n        AuthBase.__init__(self, **kwargs)\n        if self.userInfoProvider is None:\n            self.userInfoProvider = UserInfoProviderBase()\n        self.credentialFactories = credentialFactories\n        self.checkers = checkers\n\n    def getLoginResource(self):\n        return HTTPAuthSessionWrapper(\n            Portal(AuthRealm(self.master, self), self.checkers),\n            self.credentialFactories)\n\n\nclass HTPasswdAuth(TwistedICredAuthBase):\n\n    def __init__(self, passwdFile, **kwargs):\n        TwistedICredAuthBase.__init__(\n            self,\n            [DigestCredentialFactory(b\"md5\", b\"buildbot\"),\n             BasicCredentialFactory(b\"buildbot\")],\n            [FilePasswordDB(passwdFile)],\n            **kwargs)\n\n\nclass UserPasswordAuth(TwistedICredAuthBase):\n\n    def __init__(self, users, **kwargs):\n        if isinstance(users, dict):\n            users = {user: unicode2bytes(pw) for user, pw in users.items()}\n        elif isinstance(users, list):\n            users = [(user, unicode2bytes(pw)) for user, pw in users]\n        TwistedICredAuthBase.__init__(\n            self,\n            [DigestCredentialFactory(b\"md5\", b\"buildbot\"),\n             BasicCredentialFactory(b\"buildbot\")],\n            [InMemoryUsernamePasswordDatabaseDontUse(**dict(users))],\n            **kwargs)\n\n\n@implementer(ICredentialsChecker)\nclass CustomAuth(TwistedICredAuthBase):\n    __metaclass__ = ABCMeta\n    credentialInterfaces = [IUsernamePassword]\n\n    def __init__(self, **kwargs):\n        TwistedICredAuthBase.__init__(\n            self,\n            [BasicCredentialFactory(b\"buildbot\")],\n            [self],\n            **kwargs)\n\n    def requestAvatarId(self, cred):\n        if self.check_credentials(cred.username, cred.password):\n            return defer.succeed(cred.username)\n        return defer.fail(UnauthorizedLogin())\n\n    @abstractmethod\n    def check_credentials(username, password):\n        return False\n\n\ndef _redirect(master, request):\n    url = request.args.get(b\"redirect\", [b\"/\"])[0]\n    url = bytes2unicode(url)\n    return resource.Redirect(master.config.buildbotURL + \"#\" + url)\n\n\nclass PreAuthenticatedLoginResource(LoginResource):\n    # a LoginResource which is already authenticated via a\n    # HTTPAuthSessionWrapper\n\n    def __init__(self, master, username):\n        LoginResource.__init__(self, master)\n        self.username = username\n\n    @defer.inlineCallbacks\n    def renderLogin(self, request):\n        session = request.getSession()\n        session.user_info = dict(username=bytes2unicode(self.username))\n        yield self.master.www.auth.updateUserInfo(request)\n        raise _redirect(self.master, request)\n\n\nclass LogoutResource(resource.Resource):\n\n    def render_GET(self, request):\n        session = request.getSession()\n        session.expire()\n        session.updateSession(request)\n        request.redirect(_redirect(self.master, request).url)\n        return b''\n", "path": "master/buildbot/www/auth.py"}]}