Add support for auth-type=form
I'm using a gerrit installation that uses neither 'basic' nor 'digest' authentication methods, but instead redirects users to a custom login form which sets a cookie to provide authentication. This commit adds a new auth-type 'form', that automates logging in through that form. Currently, the path to the form is hardcoded to '/login' and the names of the username and password fields to 'username' and 'password' respectively. If preferred, I can add configuration options for each of those too. Change-Id: I3fff38b1be3f17c753787c9eb62ede0ce60a3ece
This commit is contained in:
parent
e45faea1b3
commit
ccc5baaf9e
@ -23,9 +23,8 @@ servers:
|
||||
# username: CHANGEME
|
||||
# Your password in Gerrit (Settings -> HTTP Password). [required]
|
||||
# password: CHANGEME
|
||||
# Authentication type required by the Gerrit server. Can be 'basic' or
|
||||
# 'digest'. Defaults to 'digest' if not set or set to an unexpected
|
||||
# value.
|
||||
# Authentication type required by the Gerrit server. Can be 'basic', 'digest' or
|
||||
# 'form'. Defaults to 'digest' if not set or set to an unexpected value.
|
||||
# auth-type: digest
|
||||
# A location where Gertty should store its git repositories. These
|
||||
# can be the same git repositories where you do your own work --
|
||||
|
68
gertty/auth.py
Normal file
68
gertty/auth.py
Normal file
@ -0,0 +1,68 @@
|
||||
# Copyright 2015 Christoph Gysin <christoph.gysin@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import requests
|
||||
import urlparse
|
||||
|
||||
|
||||
class FormAuth(requests.auth.AuthBase):
|
||||
|
||||
def __init__(self, username, password):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.log = logging.getLogger('gertty.auth')
|
||||
|
||||
def _retry_using_form_auth(self, response, args):
|
||||
adapter = requests.adapters.HTTPAdapter()
|
||||
request = _copy_request(response.request)
|
||||
|
||||
u = urlparse.urlparse(response.url)
|
||||
url = urlparse.urlunparse([u.scheme, u.netloc, '/login',
|
||||
None, None, None])
|
||||
auth = {'username': self.username,
|
||||
'password': self.password}
|
||||
request2 = requests.Request('POST', url, data=auth).prepare()
|
||||
response2 = adapter.send(request2, **args)
|
||||
|
||||
if response2.status_code == 401:
|
||||
self.log.error('Login failed: Invalid username or password?')
|
||||
return response
|
||||
|
||||
cookie = response2.headers.get('set-cookie')
|
||||
if cookie is not None:
|
||||
request.headers['Cookie'] = cookie
|
||||
|
||||
response3 = adapter.send(request, **args)
|
||||
return response3
|
||||
|
||||
def _response_hook(self, response, **kwargs):
|
||||
if response.status_code == 401:
|
||||
return self._retry_using_form_auth(response, kwargs)
|
||||
return response
|
||||
|
||||
def __call__(self, request):
|
||||
request.headers["Connection"] = "Keep-Alive"
|
||||
request.register_hook('response', self._response_hook)
|
||||
return request
|
||||
|
||||
|
||||
def _copy_request(request):
|
||||
new_request = requests.PreparedRequest()
|
||||
new_request.method = request.method
|
||||
new_request.url = request.url
|
||||
new_request.body = request.body
|
||||
new_request.hooks = request.hooks
|
||||
new_request.headers = request.headers.copy()
|
||||
return new_request
|
@ -165,7 +165,7 @@ class Config(object):
|
||||
"Permissions are: {}".format(self.path, oct(mode)))
|
||||
exit(1)
|
||||
self.auth_type = server.get('auth-type', 'digest')
|
||||
auth_types = ['digest', 'basic']
|
||||
auth_types = ['digest', 'basic', 'form']
|
||||
if self.auth_type not in auth_types:
|
||||
self.auth_type = 'digest'
|
||||
self.verify_ssl = server.get('verify-ssl', True)
|
||||
|
@ -37,6 +37,7 @@ from six.moves.urllib import parse as urlparse
|
||||
|
||||
import gertty.version
|
||||
from gertty import gitrepo
|
||||
from gertty.auth import FormAuth
|
||||
|
||||
HIGH_PRIORITY=0
|
||||
NORMAL_PRIORITY=1
|
||||
@ -1306,6 +1307,8 @@ class Sync(object):
|
||||
self.session = requests.Session()
|
||||
if self.app.config.auth_type == 'basic':
|
||||
authclass = requests.auth.HTTPBasicAuth
|
||||
elif self.app.config.auth_type == 'form':
|
||||
authclass = FormAuth
|
||||
else:
|
||||
authclass = requests.auth.HTTPDigestAuth
|
||||
self.auth = authclass(
|
||||
|
Loading…
x
Reference in New Issue
Block a user