Ticket #138: 0012-Implement-an-LDAP-based-authentication-for-the-WebSt.patch

File 0012-Implement-an-LDAP-based-authentication-for-the-WebSt.patch, 6.4 KB (added by tsuna, 4 years ago)

[PATCH v4 12/12] Implement an LDAP based authentication for the WebStatus?.

  • NEWS

    From b12ff7ed082480bd04d80d9affdf78e8ea0b60c6 Mon Sep 17 00:00:00 2001
    From: Benoit Sigoure <tsuna@lrde.epita.fr>
    Date: Sun, 18 Nov 2007 18:46:04 +0100
    Subject: [PATCH v4 12/12] Implement an LDAP based authentication for the WebStatus.
    
    	* NEWS: Mention the change.
    	* buildbot/status/web/authentication.py (LDAPAuth): New class.
    	* docs/buildbot.texinfo (WebStatus Configuration Parameters):
    	Document the new feature.
    
    Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>
    ---
     NEWS                                  |    3 +-
     buildbot/status/web/authentication.py |  101 +++++++++++++++++++++++++++++++++
     docs/buildbot.texinfo                 |    9 +++-
     3 files changed, 111 insertions(+), 2 deletions(-)
    
    diff --git a/NEWS b/NEWS
    index 2a87f27..a9949b9 100644
    a b that start builds on all Builders at once. 
    1414The WebStatus constructor can take an instance of IAuth (from 
    1515status.web.authentication).  The class BasicAuth accepts a `userpass' keyword 
    1616argument in pretty much the same way as Try_Userpass does.  The class 
    17 HTPasswdAuth authenticate users with a .htpasswd-style file. 
     17HTPasswdAuth authenticate users with a .htpasswd-style file.  The class 
     18LDAPAuth authenticate users with an LDAP directory (requires python-ldap). 
    1819Only users with a valid login/password can then force/stop builds from the 
    1920WebStatus. 
    2021 
  • buildbot/status/web/authentication.py

    diff --git a/buildbot/status/web/authentication.py b/buildbot/status/web/authentication.py
    index 1c36d78..6a7aa3c 100644
    a b class HTPasswdAuth(AuthBase): 
    8383        else: 
    8484            self.err = "Invalid password" 
    8585        return res 
     86 
     87class LDAPAuth(AuthBase): 
     88    implements(IAuth) 
     89    """Implement a synchronous authentication with an LDAP directory.""" 
     90 
     91    basedn = "" 
     92    """Base DN (Distinguished Name): the root of the LDAP directory tree 
     93 
     94    e.g.: ou=people,dc=subdomain,dc=company,dc=com""" 
     95 
     96    binddn = "" 
     97    """The bind DN is the user on the external LDAP server permitted to 
     98    search the LDAP directory.  You can leave this empty.""" 
     99 
     100    passwd = "" 
     101    """Password required to query the LDAP server.  Leave this empty if 
     102    you can query the server without password.""" 
     103 
     104    host = "" 
     105    """Hostname of the LDAP server""" 
     106 
     107    search = "" 
     108    """Template string to use to search the user trying to login in the 
     109    LDAP directory""" 
     110 
     111    def __init__(self, host, basedn, binddn="", passwd="", 
     112                 search="(uid=%s)"): 
     113        """Authenticate users against the LDAP server on C{host}. 
     114 
     115        The arguments are documented above.""" 
     116        self.host = host 
     117        self.basedn = basedn 
     118        self.binddn = binddn 
     119        self.passwd = passwd 
     120        self.search = search 
     121 
     122        self.search_conn = None 
     123        self.connect() 
     124 
     125    def connect(self): 
     126        """Setup the connections with the LDAP server.""" 
     127        import ldap 
     128        # Close existing connections 
     129        if self.search_conn: 
     130            self.search_conn.unbind() 
     131        # Connection used to locate the users in the LDAP DB. 
     132        self.search_conn = ldap.open(self.host) 
     133        self.search_conn.bind_s(self.binddn, self.passwd, 
     134                                ldap.AUTH_SIMPLE) 
     135 
     136    def authenticate(self, login, password): 
     137        """Authenticate the C{login} / C{password} with the LDAP server.""" 
     138        import ldap 
     139        # Python-LDAP raises all sorts of exceptions to express various 
     140        # failures, let's catch them all here and assume that if 
     141        # anything goes wrong, the authentication failed. 
     142        try: 
     143            res = self._authenticate(login, password) 
     144            if res: 
     145                self.err = "" 
     146            return res 
     147        except ldap.LDAPError, e: 
     148            self.err = "LDAP error: " + str(e) 
     149            return False 
     150        except: 
     151            self.err = "unknown error" 
     152            return False 
     153 
     154    def _authenticate(self, login, password): 
     155        import ldap 
     156        # Search the login in the LDAP DB 
     157        try: 
     158            result = self.search_conn.search_s(self.basedn, 
     159                                               ldap.SCOPE_SUBTREE, 
     160                                               self.search % login, 
     161                                               ['objectclass'], 1) 
     162        except ldap.SERVER_DOWN: 
     163            self.err = "LDAP server seems down" 
     164            # Try to reconnect... 
     165            self.connect() 
     166            # FIXME: Check that this can't lead to an infinite recursion 
     167            return self.authenticate(login, password) 
     168 
     169        # Make sure we found a single user in the LDAP DB 
     170        if not result or len(result) != 1: 
     171            self.err = "user not found in the LDAP DB" 
     172            return False 
     173 
     174        # Connection used to authenticate users with the LDAP DB. 
     175        auth_conn = ldap.open(self.host) 
     176        # DN associated to this user 
     177        ldap_dn = result[0][0] 
     178        #log.msg('using ldap_dn = ' + ldap_dn) 
     179        # Authenticate the user 
     180        try: 
     181            auth_conn.bind_s(ldap_dn, password, ldap.AUTH_SIMPLE) 
     182        except ldap.INVALID_CREDENTIALS: 
     183            self.err = "invalid credentials" 
     184            return False 
     185        auth_conn.unbind() 
     186        return True 
  • docs/buildbot.texinfo

    diff --git a/docs/buildbot.texinfo b/docs/buildbot.texinfo
    index e16ee40..dc937c4 100644
    a b current builds, in that case you can pass an instance of 
    61286128The class @code{BasicAuth} implements a basic authentication mechanism 
    61296129using a list of login/password pairs provided from the configuration file. 
    61306130The class @code{HTPasswdAuth} implements an authentication against an 
    6131 @file{.htpasswd}-style file. 
     6131@file{.htpasswd}-style file.  The class @code{LDAPAuth} authenticates 
     6132the users with an LDAP database.  It requires 
     6133@uref{http://python-ldap.sourceforge.net/, python-ldap}. 
    61326134 
    61336135@example 
    61346136from buildbot.status.html import WebStatus 
    c['status'].append(WebStatus(http_port=8080, auth=BasicAuth(users))) 
    61396141from buildbot.status.web.authentication import HTPasswdAuth 
    61406142file = '/path/to/file' 
    61416143c['status'].append(WebStatus(http_port=8080, auth=HTPasswdAuth(file))) 
     6144 
     6145from buildbot.status.web.authentication import LDAPAuth 
     6146c['status'].append(WebStatus(http_port=8080, 
     6147                             auth=LDAPAuth('ldap.server.company.com', 
     6148                                           'ou=people,dc=company,dc=com')) 
    61426149@end example 
    61436150 
    61446151