From af2cbe8a5bec2b7971de137416d6e62ac1b96498 Mon Sep 17 00:00:00 2001 From: Prashanth Pai Date: Mon, 23 Sep 2013 11:47:21 +0530 Subject: Minor swiftkerbauth changes * Replaced python-webob with swift.common.swob * Use swift memcached instead of python memcached * Added optional debugging headers to swift-auth script * Swiftkerbauth and Apachekerbauth are now a single RPM * Updates to httpd conf file to specify Kerberos principal * Added setupy.py, makerpm.sh, .gitignore and MANIFEST.in * RPM is now generated by bdist_rpm using setup.py and not from spec files TODO -> Documentation changes in doc/ * Steps to setup kerberos environment * Swiftkerbauth usage and examples -> Testing swiftkerbauth * Investigate borrowing tests from tempauth.py and its dependencies * Write a python client script to test swiftkerbauth Signed-off-by: Prashanth Pai --- apachekerbauth/var/www/cgi-bin/swift-auth | 123 ++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100755 apachekerbauth/var/www/cgi-bin/swift-auth (limited to 'apachekerbauth/var') diff --git a/apachekerbauth/var/www/cgi-bin/swift-auth b/apachekerbauth/var/www/cgi-bin/swift-auth new file mode 100755 index 0000000..6173408 --- /dev/null +++ b/apachekerbauth/var/www/cgi-bin/swift-auth @@ -0,0 +1,123 @@ +#!/usr/bin/python + +# Copyright (c) 2013 Red Hat, Inc. +# +# 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. + +# Requires the following command to be run: +# setsebool -P httpd_can_network_connect 1 +# setsebool -P httpd_can_network_memcache 1 + +import cgi +from swift.common.memcached import MemcacheRing +import os +import grp +import random +import re +import subprocess +from time import time, ctime + +# After how many seconds the cached information about an authentication +# token is discarded. +TOKEN_LIFE = 86400 + +# This is used as a prefix for tokens and memcache keys. We use the default +# value from the Swift tempauth filter. In the future, this should be turned +# into a configuration parameter. +RESELLER_PREFIX = 'AUTH_' + +MEMCACHE_SERVERS = ['127.0.0.1:11211'] + +DEBUG_HEADERS = True + +def main(): + remote_user = os.environ['REMOTE_USER'] + matches = re.match('([^@]+)@.*', remote_user) + if not matches: + raise RuntimeError("Malformed REMOTE_USER \"%s\"" % remote_user) + + username = matches.group(1) + + mc = MemcacheRing(MEMCACHE_SERVERS) + + # Check if we already got a token for this user. + memcache_user_key = '%s/user/%s' % (RESELLER_PREFIX, username) + token = None + candidate_token = mc.get(memcache_user_key) + if candidate_token: + memcache_token_key = '%s/token/%s' % (RESELLER_PREFIX, candidate_token) + cached_auth_data = mc.get(memcache_token_key) + if cached_auth_data: + expires, groups = cached_auth_data + if expires > time(): + token = candidate_token + + if not token: + # We don't use uuid.uuid4() here because importing the uuid module + # causes (harmless) SELinux denials in the audit log on RHEL 6. If this + # is a security concern, a custom SELinux policy module could be + # written to not log those denials. + r = random.SystemRandom() + token = '%stk%s' % \ + (RESELLER_PREFIX, + ''.join(r.choice('abcdef0123456789') for x in range(32))) + + # Retrieve the numerical group IDs. We cannot list the group names + # because group names from Active Directory may contain spaces, and + # we wouldn't be able to split the list of group names into its + # elements. + p = subprocess.Popen(['id', '-G', username], stdout=subprocess.PIPE) + if p.wait() != 0: + raise RuntimeError("Failure running id -G for %s" % remote_user) + + (p_stdout, p_stderr) = p.communicate() + + # Convert the group numbers into group names. + groups = [] + for gid in p_stdout.strip().split(" "): + groups.append(grp.getgrgid(int(gid))[0]) + + # The first element of the list is considered a unique identifier + # for the user. We add the username to accomplish this. + if username in groups: + groups.remove(username) + groups = [username] + groups + + groups = ','.join(groups) + + expires = time() + TOKEN_LIFE + auth_data = (expires, groups) + + memcache_token_key = "%s/token/%s" % (RESELLER_PREFIX, token) + mc.set(memcache_token_key, auth_data, timeout=TOKEN_LIFE) + + # Record the token with the user info for future use. + memcache_user_key = '%s/user/%s' % (RESELLER_PREFIX, username) + mc.set(memcache_user_key, token, timeout=TOKEN_LIFE) + + print "X-Auth-Token: %s" % token + + # For debugging. + if DEBUG_HEADERS: + print "X-Debug-Remote-User: %s" % username + print "X-Debug-Groups: %s" % groups + print "X-Debug-Token-Life: %ss" % TOKEN_LIFE + print "X-Debug-Token-Expires: %s" % ctime(expires) + + print "" + +try: + print("Content-Type: text/html") + main() +except: + cgi.print_exception() -- cgit