summaryrefslogtreecommitdiffstats
path: root/swiftkerbauth
diff options
context:
space:
mode:
authorPrashanth Pai <ppai@redhat.com>2013-11-06 17:30:28 +0530
committerLuis Pabon <lpabon@redhat.com>2013-11-17 16:34:11 -0800
commit991989bc04178442b2a6b766a67f7a26e60c08f0 (patch)
treee796215fbb45333290fdd293b608235b7f67493c /swiftkerbauth
parentf64a3354185f32928e2568d9ece4a52fa4746c05 (diff)
Modularize swift-auth CGI script, add unit tests
- Moved most of swift-auth CGI script to kerbauth_utils.py - Added unit tests for kerbauth_utils.py - Made MEMCACHE_SERVERS, DEBUG_HEADERS, TOKEN_LIFE as configurable parameters Change-Id: I2e9e9823e8aa99dc2cf41327c55428350c8768dc Signed-off-by: Prashanth Pai <ppai@redhat.com> Reviewed-on: http://review.gluster.org/6248 Tested-by: Chetan Risbud <crisbud@redhat.com> Reviewed-by: Chetan Risbud <crisbud@redhat.com> Reviewed-by: Luis Pabon <lpabon@redhat.com> Tested-by: Luis Pabon <lpabon@redhat.com>
Diffstat (limited to 'swiftkerbauth')
-rw-r--r--swiftkerbauth/__init__.py21
-rw-r--r--swiftkerbauth/kerbauth.py8
-rw-r--r--swiftkerbauth/kerbauth_utils.py106
3 files changed, 128 insertions, 7 deletions
diff --git a/swiftkerbauth/__init__.py b/swiftkerbauth/__init__.py
index eaa1d88..abdbeaa 100644
--- a/swiftkerbauth/__init__.py
+++ b/swiftkerbauth/__init__.py
@@ -14,4 +14,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "1.0.0"
+
+from swift.common.utils import readconf, config_true_value
+
+config_file = {}
+try:
+ config_file = readconf("/etc/swift/proxy-server.conf",
+ section_name="filter:cache")
+except SystemExit:
+ pass
+MEMCACHE_SERVERS = config_file.get('memcache_servers', None)
+
+config_file = {}
+try:
+ config_file = readconf("/etc/swift/proxy-server.conf",
+ section_name="filter:kerbauth")
+except SystemExit:
+ pass
+TOKEN_LIFE = int(config_file.get('token_life', 86400))
+RESELLER_PREFIX = config_file.get('reseller_prefix', "AUTH_")
+DEBUG_HEADERS = config_true_value(config_file.get('debug_headers', 'yes'))
diff --git a/swiftkerbauth/kerbauth.py b/swiftkerbauth/kerbauth.py
index 612299d..a1ba091 100644
--- a/swiftkerbauth/kerbauth.py
+++ b/swiftkerbauth/kerbauth.py
@@ -17,12 +17,8 @@ from traceback import format_exc
from eventlet import Timeout
from swift.common.swob import Request
-from swift.common.swob import HTTPBadRequest, HTTPForbidden, HTTPNotFound
-
-try:
- from swift.common.swob import HTTPSeeOther
-except ImportError:
- from swift.common.swob import HTTPFound as HTTPSeeOther
+from swift.common.swob import HTTPBadRequest, HTTPForbidden, HTTPNotFound, \
+ HTTPSeeOther
from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
from swift.common.utils import cache_from_env, get_logger, \
diff --git a/swiftkerbauth/kerbauth_utils.py b/swiftkerbauth/kerbauth_utils.py
new file mode 100644
index 0000000..507580e
--- /dev/null
+++ b/swiftkerbauth/kerbauth_utils.py
@@ -0,0 +1,106 @@
+# 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.
+
+import re
+import random
+import grp
+import subprocess
+from time import time
+from swiftkerbauth import TOKEN_LIFE, RESELLER_PREFIX
+
+
+def get_remote_user(env):
+ """Retrieve REMOTE_USER set by Apache from environment."""
+ remote_user = env.get('REMOTE_USER', "")
+ matches = re.match('([^@]+)@.*', remote_user)
+ if not matches:
+ raise RuntimeError("Malformed REMOTE_USER \"%s\"" % remote_user)
+ return matches.group(1)
+
+
+def get_auth_data(mc, username):
+ """
+ Returns the token, expiry time and groups for the user if it already exists
+ on memcache. Returns None otherwise.
+
+ :param mc: MemcacheRing object
+ :param username: swift user
+ """
+ token, expires, groups = None, None, None
+ memcache_user_key = '%s/user/%s' % (RESELLER_PREFIX, username)
+ 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
+ else:
+ expires, groups = None, None
+ return (token, expires, groups)
+
+
+def set_auth_data(mc, username, token, expires, groups):
+ """
+ Stores the following key value pairs on Memcache:
+ (token, expires+groups)
+ (user, token)
+ """
+ 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)
+
+
+def generate_token():
+ """Generates a random 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)))
+ return token
+
+
+def get_groups(username):
+ """Return a set of groups to which the user belongs to."""
+ # 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" % username)
+ (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)
+ return groups