116 lines
4.4 KiB
Python
116 lines
4.4 KiB
Python
# Copyright (C) 2011 Apple Inc. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
|
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
"""An implementation of buildbot.status.web.auth.IAuth for authenticating WebKit committers"""
|
|
|
|
import ConfigParser
|
|
import buildbot.status.web.auth
|
|
import json
|
|
import zope.interface
|
|
|
|
from htdigestparser import HTDigestParser
|
|
|
|
|
|
class Error(Exception):
|
|
pass
|
|
|
|
|
|
class CommitterAuth(buildbot.status.web.auth.AuthBase):
|
|
zope.interface.implements(buildbot.status.web.auth.IAuth)
|
|
|
|
def __init__(self, auth_json_filename):
|
|
self._auth_json_filename = auth_json_filename
|
|
|
|
def auth_json(self):
|
|
try:
|
|
with self.open_auth_json_file() as f:
|
|
return json.load(f)
|
|
except IOError as e:
|
|
raise Error('Error opening auth.json file: {0}'.format(e.strerror))
|
|
except ValueError as e:
|
|
raise Error('Error parsing auth.json file: {0}'.format(e.message))
|
|
|
|
def auth_json_filename(self):
|
|
return self._auth_json_filename
|
|
|
|
def authenticate(self, username, password):
|
|
try:
|
|
return self.is_webkit_committer(username) and self.is_webkit_trac_user(username, password)
|
|
except Error as e:
|
|
self.err = e.args[0]
|
|
return False
|
|
|
|
def is_webkit_committer(self, username):
|
|
try:
|
|
if username not in self.webkit_committers():
|
|
self.err = 'Invalid username/password'
|
|
return False
|
|
return True
|
|
except ConfigParser.Error:
|
|
raise Error('Error parsing WebKit committers file')
|
|
except IOError as e:
|
|
raise Error('Error opening WebKit committers file: {0}'.format(e.strerror))
|
|
|
|
def is_webkit_trac_user(self, username, password):
|
|
try:
|
|
with self.open_trac_credentials_file() as f:
|
|
htdigest = HTDigestParser(f)
|
|
except IOError as e:
|
|
raise Error('Error opening Trac credentials file: {0}'.format(e.strerror))
|
|
|
|
if not htdigest.entries():
|
|
raise Error('Error parsing Trac credentials file')
|
|
|
|
if not htdigest.authenticate(username, 'Mac OS Forge', password):
|
|
self.err = 'Invalid username/password'
|
|
return False
|
|
|
|
return True
|
|
|
|
# These three methods exist for ease of testing.
|
|
def open_auth_json_file(self):
|
|
return open(self.auth_json_filename())
|
|
|
|
def open_trac_credentials_file(self):
|
|
return open(self.trac_credentials_filename())
|
|
|
|
def open_webkit_committers_file(self):
|
|
return open(self.webkit_committers_filename())
|
|
|
|
def trac_credentials_filename(self):
|
|
try:
|
|
return self.auth_json()['trac_credentials']
|
|
except KeyError:
|
|
raise Error('auth.json file is missing "trac_credentials" key')
|
|
|
|
def webkit_committers(self):
|
|
config = ConfigParser.RawConfigParser()
|
|
with self.open_webkit_committers_file() as f:
|
|
config.readfp(f)
|
|
return config.get('groups', 'webkit').split(',')
|
|
|
|
def webkit_committers_filename(self):
|
|
try:
|
|
return self.auth_json()['webkit_committers']
|
|
except KeyError:
|
|
raise Error('auth.json file is missing "webkit_committers" key')
|