summaryrefslogtreecommitdiffstats
path: root/gluster/swift/common/middleware/swiftkerbauth
diff options
context:
space:
mode:
authorThiago da Silva <thiago@redhat.com>2014-04-22 14:15:02 -0400
committerPrashanth Pai <ppai@redhat.com>2016-01-06 07:53:12 -0800
commit2a8f9f0f530327039c32e444b6a27130b12666bd (patch)
treee24e38b5b3c0245a0acafc63fc50bacbf7de718a /gluster/swift/common/middleware/swiftkerbauth
parent4c6ca1db931377b75583f61a7bca262cfc27b0fa (diff)
Update repo
This is a squashed commit imported from this repo: https://github.com/openstack/swiftonfile/tree/icehouse Contains the follwing commits from above mentioned repo: eb50236 Merge "Backport: Fix metadata overall limits bug" into icehouse 79ea52a Backport: Fix metadata overall limits bug bc43f0b Fix inconsistent data being returned on GET ad0bb79 Import HTTPBadRequest from swift's module 74d02e6 Exclude .trashcan dir from container listing b2dbc15 Catch ESTALE in addition to ENOENT 8d60b48 Properly handle read_metadata() exceptions 6762fc6 Fix object server leaking file descriptors 2842e82 Fix API incompatibility in update_metadata() 2beeef6 Merge "Remove swiftkerbauth code" into icehouse 93dbcb5 Update object-expirer.conf with explanations c9d2f09 Merge "Check if /etc/swift exists in ring builder" into icehouse d66c14c Remove swiftkerbauth code 3142ed2 Add object expiration functests 97153d1 Merge "Cleanup functest and undo old patch" into icehouse bc234d0 Remove old travis config file and fix typo 260c8ef Check if /etc/swift exists in ring builder 637dac9 Cleanup functest and undo old patch 051e068 Merge pull request #35 from prashanthpai/backport-1 be104a3 Merge pull request #36 from prashanthpai/backport-2 ff76f42 fix issue with GET on large object (icehouse-backport) 04d0a99 Fix unlink call after successful rename 4c6ca1d updating README file with project name change 10b2680 Merge pull request #18 from thiagol11/icehouse 5bcab8f Updating version on __init__ file 5c2cba2 Merge pull request #15 from thiagol11/update_spec 52b00a8 updating spec file to add dependency on swift icehouse ae7c93b Merge pull request #6 from prashanthpai/rebase 191e55b Revert: allow non-root user to run functests cb7e968 Modify unit tests and func tests d23fd1b Sync with OpenStack Swift v1.13.1 b6d1671 Merge pull request #12 from pushpesh/functionalnosetestremove 962622b Merge pull request #8 from thiagol11/update_readme 4560857 Merge pull request #9 from prashanthpai/spec-expirer be0ae7e Minor update 65000f1 Removing functionalnosetests 8ab1069 Fix object-expirer.conf-gluster RPM build error afee30f added new support filesystem section 527b01f updated README.md to Swift-On-File 9a240c7 Merge pull request #3 from thiagol11/add_jenkins_to_travis 34b5a8b removing blank lines 3568b64 fixing missing fi d8f5b0f adding support to run jenkins triggered by travis 6f4a88c Removing functionalnosetests 8041944 Update README.md c015148 Merge pull request #2 from thiagol11/master 3ddd952 fixing travis file to run correct unit test c582669 adding travis status badge to README 8093096 adding py26 unit testing to travis 37835fd trigger travis build cb6332a adding travis ci testing All tests have been run sucessfully against this. tox -e p2p8,py27,functest Change-Id: I096b611da852d3eb3913844034b443b8272c2ac4 Signed-off-by: Prashanth Pai <ppai@redhat.com> Reviewed-on: http://review.gluster.org/13188
Diffstat (limited to 'gluster/swift/common/middleware/swiftkerbauth')
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/__init__.py38
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf12
-rwxr-xr-xgluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth70
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/kerbauth.py463
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py137
5 files changed, 0 insertions, 720 deletions
diff --git a/gluster/swift/common/middleware/swiftkerbauth/__init__.py b/gluster/swift/common/middleware/swiftkerbauth/__init__.py
deleted file mode 100644
index c752df7..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env 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.
-
-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/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf b/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf
deleted file mode 100644
index 68472d8..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-<Location /cgi-bin/swift-auth>
- AuthType Kerberos
- AuthName "Swift Authentication"
- KrbMethodNegotiate On
- KrbMethodK5Passwd On
- KrbSaveCredentials On
- KrbServiceName HTTP/client.example.com
- KrbAuthRealms EXAMPLE.COM
- Krb5KeyTab /etc/httpd/conf/http.keytab
- KrbVerifyKDC Off
- Require valid-user
-</Location>
diff --git a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth b/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth
deleted file mode 100755
index 11fe0e2..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/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 os
-import cgi
-from swift.common.memcached import MemcacheRing
-from time import time, ctime
-from swiftkerbauth import MEMCACHE_SERVERS, TOKEN_LIFE, DEBUG_HEADERS
-from swiftkerbauth.kerbauth_utils import get_remote_user, get_auth_data, \
- generate_token, set_auth_data, get_groups_from_username
-
-
-def main():
- try:
- username = get_remote_user(os.environ)
- except RuntimeError:
- print "Status: 401 Unauthorized\n"
- print "Malformed REMOTE_USER"
- return
-
- if not MEMCACHE_SERVERS:
- print "Status: 500 Internal Server Error\n"
- print "Memcache not configured in /etc/swift/proxy-server.conf"
- return
-
- mc_servers = [s.strip() for s in MEMCACHE_SERVERS.split(',') if s.strip()]
- mc = MemcacheRing(mc_servers)
-
- token, expires, groups = get_auth_data(mc, username)
-
- if not token:
- token = generate_token()
- expires = time() + TOKEN_LIFE
- groups = get_groups_from_username(username)
- set_auth_data(mc, username, token, expires, groups)
-
- print "X-Auth-Token: %s" % token
- print "X-Storage-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()
diff --git a/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py b/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py
deleted file mode 100644
index 1a63a40..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py
+++ /dev/null
@@ -1,463 +0,0 @@
-# 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 errno
-from time import time, ctime
-from traceback import format_exc
-from eventlet import Timeout
-from urllib import unquote
-
-from swift.common.swob import Request, Response
-from swift.common.swob import HTTPBadRequest, HTTPForbidden, HTTPNotFound, \
- HTTPSeeOther, HTTPUnauthorized, HTTPServerError
-
-from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
-from swift.common.utils import cache_from_env, get_logger, \
- split_path, config_true_value
-from gluster.swift.common.middleware.swiftkerbauth.kerbauth_utils import \
- get_auth_data, generate_token, \
- set_auth_data, run_kinit, get_groups_from_username
-
-
-class KerbAuth(object):
- """
- Test authentication and authorization system.
-
- Add to your pipeline in proxy-server.conf, such as::
-
- [pipeline:main]
- pipeline = catch_errors cache kerbauth proxy-server
-
- Set account auto creation to true in proxy-server.conf::
-
- [app:proxy-server]
- account_autocreate = true
-
- And add a kerbauth filter section, such as::
-
- [filter:kerbauth]
- use = egg:swiftkerbauth#kerbauth
-
- See the proxy-server.conf-sample for more information.
-
- :param app: The next WSGI app in the pipeline
- :param conf: The dict of configuration values
- """
-
- def __init__(self, app, conf):
- self.app = app
- self.conf = conf
- self.logger = get_logger(conf, log_route='kerbauth')
- self.log_headers = config_true_value(conf.get('log_headers', 'f'))
- self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
- if self.reseller_prefix and self.reseller_prefix[-1] != '_':
- self.reseller_prefix += '_'
- self.logger.set_statsd_prefix('kerbauth.%s' % (
- self.reseller_prefix if self.reseller_prefix else 'NONE',))
- self.auth_prefix = conf.get('auth_prefix', '/auth/')
- if not self.auth_prefix or not self.auth_prefix.strip('/'):
- self.logger.warning('Rewriting invalid auth prefix "%s" to '
- '"/auth/" (Non-empty auth prefix path '
- 'is required)' % self.auth_prefix)
- self.auth_prefix = '/auth/'
- if self.auth_prefix[0] != '/':
- self.auth_prefix = '/' + self.auth_prefix
- if self.auth_prefix[-1] != '/':
- self.auth_prefix += '/'
- self.token_life = int(conf.get('token_life', 86400))
- self.auth_method = conf.get('auth_method', 'passive')
- self.debug_headers = config_true_value(
- conf.get('debug_headers', 'yes'))
- self.realm_name = conf.get('realm_name', None)
- self.allow_overrides = config_true_value(
- conf.get('allow_overrides', 't'))
- self.storage_url_scheme = conf.get('storage_url_scheme', 'default')
- self.ext_authentication_url = conf.get('ext_authentication_url')
- if not self.ext_authentication_url:
- raise RuntimeError("Missing filter parameter ext_authentication_"
- "url in /etc/swift/proxy-server.conf")
-
- def __call__(self, env, start_response):
- """
- Accepts a standard WSGI application call, authenticating the request
- and installing callback hooks for authorization and ACL header
- validation. For an authenticated request, REMOTE_USER will be set to a
- comma separated list of the user's groups.
-
- If the request matches the self.auth_prefix, the request will be
- routed through the internal auth request handler (self.handle).
- This is to handle granting tokens, etc.
- """
- if self.allow_overrides and env.get('swift.authorize_override', False):
- return self.app(env, start_response)
- if env.get('PATH_INFO', '').startswith(self.auth_prefix):
- return self.handle(env, start_response)
- token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
- if token and token.startswith(self.reseller_prefix):
- groups = self.get_groups(env, token)
- if groups:
- user = groups and groups.split(',', 1)[0] or ''
- trans_id = env.get('swift.trans_id')
- self.logger.debug('User: %s uses token %s (trans_id %s)' %
- (user, token, trans_id))
- env['REMOTE_USER'] = groups
- env['swift.authorize'] = self.authorize
- env['swift.clean_acl'] = clean_acl
- if '.reseller_admin' in groups:
- env['reseller_request'] = True
- else:
- # Invalid token (may be expired)
- if self.auth_method == "active":
- return HTTPSeeOther(
- location=self.ext_authentication_url)(env,
- start_response)
- elif self.auth_method == "passive":
- self.logger.increment('unauthorized')
- return HTTPUnauthorized()(env, start_response)
- else:
- # With a non-empty reseller_prefix, I would like to be called
- # back for anonymous access to accounts I know I'm the
- # definitive auth for.
- try:
- version, rest = split_path(env.get('PATH_INFO', ''),
- 1, 2, True)
- except ValueError:
- version, rest = None, None
- self.logger.increment('errors')
- # Not my token, not my account, I can't authorize this request,
- # deny all is a good idea if not already set...
- if 'swift.authorize' not in env:
- env['swift.authorize'] = self.denied_response
-
- return self.app(env, start_response)
-
- def get_groups(self, env, token):
- """
- Get groups for the given token.
-
- :param env: The current WSGI environment dictionary.
- :param token: Token to validate and return a group string for.
-
- :returns: None if the token is invalid or a string containing a comma
- separated list of groups the authenticated user is a member
- of. The first group in the list is also considered a unique
- identifier for that user.
- """
- groups = None
- memcache_client = cache_from_env(env)
- if not memcache_client:
- raise Exception('Memcache required')
- memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
- cached_auth_data = memcache_client.get(memcache_token_key)
- if cached_auth_data:
- expires, groups = cached_auth_data
- if expires < time():
- groups = None
-
- return groups
-
- def authorize(self, req):
- """
- Returns None if the request is authorized to continue or a standard
- WSGI response callable if not.
-
- Assumes that user groups are all lower case, which is true when Red Hat
- Enterprise Linux Identity Management is used.
- """
- try:
- version, account, container, obj = req.split_path(1, 4, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
-
- if not account or not account.startswith(self.reseller_prefix):
- self.logger.debug("Account name: %s doesn't start with "
- "reseller_prefix: %s."
- % (account, self.reseller_prefix))
- return self.denied_response(req)
-
- user_groups = (req.remote_user or '').split(',')
- account_user = user_groups[1] if len(user_groups) > 1 else None
- # If the user is in the reseller_admin group for our prefix, he gets
- # full access to all accounts we manage. For the default reseller
- # prefix, the group name is auth_reseller_admin.
- admin_group = ("%sreseller_admin" % self.reseller_prefix).lower()
- if admin_group in user_groups and \
- account != self.reseller_prefix and \
- account[len(self.reseller_prefix)] != '.':
- req.environ['swift_owner'] = True
- return None
-
- # The "account" is part of the request URL, and already contains the
- # reseller prefix, like in "/v1/AUTH_vol1/pictures/pic1.png".
- if account.lower() in user_groups and \
- (req.method not in ('DELETE', 'PUT') or container):
- # If the user is admin for the account and is not trying to do an
- # account DELETE or PUT...
- req.environ['swift_owner'] = True
- self.logger.debug("User %s has admin authorizing."
- % account_user)
- return None
-
- if (req.environ.get('swift_sync_key')
- and (req.environ['swift_sync_key'] ==
- req.headers.get('x-container-sync-key', None))
- and 'x-timestamp' in req.headers):
- self.logger.debug("Allow request with container sync-key: %s."
- % req.environ['swift_sync_key'])
- return None
-
- if req.method == 'OPTIONS':
- #allow OPTIONS requests to proceed as normal
- self.logger.debug("Allow OPTIONS request.")
- return None
-
- referrers, groups = parse_acl(getattr(req, 'acl', None))
-
- if referrer_allowed(req.referer, referrers):
- if obj or '.rlistings' in groups:
- self.logger.debug("Allow authorizing %s via referer ACL."
- % req.referer)
- return None
-
- for user_group in user_groups:
- if user_group in groups:
- self.logger.debug("User %s allowed in ACL: %s authorizing."
- % (account_user, user_group))
- return None
-
- return self.denied_response(req)
-
- def denied_response(self, req):
- """
- Returns a standard WSGI response callable with the status of 403 or 401
- depending on whether the REMOTE_USER is set or not.
- """
- if req.remote_user:
- self.logger.increment('forbidden')
- return HTTPForbidden(request=req)
- else:
- if self.auth_method == "active":
- return HTTPSeeOther(location=self.ext_authentication_url)
- elif self.auth_method == "passive":
- self.logger.increment('unauthorized')
- return HTTPUnauthorized(request=req)
-
- def handle(self, env, start_response):
- """
- WSGI entry point for auth requests (ones that match the
- self.auth_prefix).
- Wraps env in swob.Request object and passes it down.
-
- :param env: WSGI environment dictionary
- :param start_response: WSGI callable
- """
- try:
- req = Request(env)
- if self.auth_prefix:
- req.path_info_pop()
- req.bytes_transferred = '-'
- req.client_disconnect = False
- if 'x-storage-token' in req.headers and \
- 'x-auth-token' not in req.headers:
- req.headers['x-auth-token'] = req.headers['x-storage-token']
- return self.handle_request(req)(env, start_response)
- except (Exception, Timeout):
- print "EXCEPTION IN handle: %s: %s" % (format_exc(), env)
- self.logger.increment('errors')
- start_response('500 Server Error',
- [('Content-Type', 'text/plain')])
- return ['Internal server error.\n']
-
- def handle_request(self, req):
- """
- Entry point for auth requests (ones that match the self.auth_prefix).
- Should return a WSGI-style callable (such as webob.Response).
-
- :param req: swob.Request object
- """
- req.start_time = time()
- handler = None
- try:
- version, account, user, _junk = req.split_path(1, 4, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
- if version in ('v1', 'v1.0', 'auth'):
- if req.method == 'GET':
- handler = self.handle_get_token
- if not handler:
- self.logger.increment('errors')
- req.response = HTTPBadRequest(request=req)
- else:
- req.response = handler(req)
- return req.response
-
- def handle_get_token(self, req):
- """
- Handles the various `request for token and service end point(s)` calls.
- There are various formats to support the various auth servers in the
- past.
-
- "Active Mode" usage:
- All formats require GSS (Kerberos) authentication.
-
- GET <auth-prefix>/v1/<act>/auth
- GET <auth-prefix>/auth
- GET <auth-prefix>/v1.0
-
- On successful authentication, the response will have X-Auth-Token
- and X-Storage-Token set to the token to use with Swift.
-
- "Passive Mode" usage::
-
- GET <auth-prefix>/v1/<act>/auth
- X-Auth-User: <act>:<usr> or X-Storage-User: <usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
- GET <auth-prefix>/auth
- X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
- GET <auth-prefix>/v1.0
- X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
-
- Values should be url encoded, "act%3Ausr" instead of "act:usr" for
- example; however, for backwards compatibility the colon may be
- included unencoded.
-
- On successful authentication, the response will have X-Auth-Token
- and X-Storage-Token set to the token to use with Swift and
- X-Storage-URL set to the URL to the default Swift cluster to use.
-
- :param req: The swob.Request to process.
- :returns: swob.Response, 2xx on success with data set as explained
- above.
- """
- # Validate the request info
- try:
- pathsegs = split_path(req.path_info, 1, 3, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
- if not ((pathsegs[0] == 'v1' and pathsegs[2] == 'auth')
- or pathsegs[0] in ('auth', 'v1.0')):
- return HTTPBadRequest(request=req)
-
- # Client is inside the domain
- if self.auth_method == "active":
- return HTTPSeeOther(location=self.ext_authentication_url)
-
- # Client is outside the domain
- elif self.auth_method == "passive":
- account, user, key = None, None, None
- # Extract user, account and key from request
- if pathsegs[0] == 'v1' and pathsegs[2] == 'auth':
- account = pathsegs[1]
- user = req.headers.get('x-storage-user')
- if not user:
- user = unquote(req.headers.get('x-auth-user', ''))
- if user:
- if ':' not in user:
- return HTTPUnauthorized(request=req)
- else:
- account2, user = user.split(':', 1)
- if account != account2:
- return HTTPUnauthorized(request=req)
- key = req.headers.get('x-storage-pass')
- if not key:
- key = unquote(req.headers.get('x-auth-key', ''))
- elif pathsegs[0] in ('auth', 'v1.0'):
- user = unquote(req.headers.get('x-auth-user', ''))
- if not user:
- user = req.headers.get('x-storage-user')
- if user:
- if ':' not in user:
- return HTTPUnauthorized(request=req)
- else:
- account, user = user.split(':', 1)
- key = unquote(req.headers.get('x-auth-key', ''))
- if not key:
- key = req.headers.get('x-storage-pass')
-
- if not (account or user or key):
- # If all are not given, client may be part of the domain
- return HTTPSeeOther(location=self.ext_authentication_url)
- elif None in (key, user, account):
- # If only one or two of them is given, but not all
- return HTTPUnauthorized(request=req)
-
- # Run kinit on the user
- if self.realm_name and "@" not in user:
- user = user + "@" + self.realm_name
- try:
- ret = run_kinit(user, key)
- except OSError as e:
- if e.errno == errno.ENOENT:
- return HTTPServerError("kinit command not found\n")
- if ret != 0:
- self.logger.warning("Failed: kinit %s", user)
- if ret == -1:
- self.logger.warning("Failed: kinit: Password has probably "
- "expired.")
- return HTTPServerError("Kinit is taking too long.\n")
- return HTTPUnauthorized(request=req)
- self.logger.debug("kinit succeeded")
-
- if "@" in user:
- user = user.split("@")[0]
-
- # Check if user really belongs to the account
- groups_list = get_groups_from_username(user).strip().split(",")
- user_group = ("%s%s" % (self.reseller_prefix, account)).lower()
- reseller_admin_group = \
- ("%sreseller_admin" % self.reseller_prefix).lower()
- if user_group not in groups_list:
- # Check if user is reseller_admin. If not, return Unauthorized.
- # On AD/IdM server, auth_reseller_admin is a separate group
- if reseller_admin_group not in groups_list:
- return HTTPUnauthorized(request=req)
-
- mc = cache_from_env(req.environ)
- if not mc:
- raise Exception('Memcache required')
- token, expires, groups = get_auth_data(mc, user)
- if not token:
- token = generate_token()
- expires = time() + self.token_life
- groups = get_groups_from_username(user)
- set_auth_data(mc, user, token, expires, groups)
-
- headers = {'X-Auth-Token': token,
- 'X-Storage-Token': token}
-
- if self.debug_headers:
- headers.update({'X-Debug-Remote-User': user,
- 'X-Debug-Groups:': groups,
- 'X-Debug-Token-Life': self.token_life,
- 'X-Debug-Token-Expires': ctime(expires)})
-
- resp = Response(request=req, headers=headers)
- resp.headers['X-Storage-Url'] = \
- '%s/v1/%s%s' % (resp.host_url, self.reseller_prefix, account)
- return resp
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return KerbAuth(app, conf)
- return auth_filter
diff --git a/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py b/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py
deleted file mode 100644
index 599ef99..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# 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 signal
-from subprocess import Popen, PIPE
-from time import time
-from gluster.swift.common.middleware.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, time=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, time=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_from_username(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 = Popen(['id', '-G', username], stdout=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
-
-
-def run_kinit(username, password):
- """Runs kinit command as a child process and returns the status code."""
- kinit = Popen(['kinit', username],
- stdin=PIPE, stdout=PIPE, stderr=PIPE)
- kinit.stdin.write('%s\n' % password)
-
- # The following code handles a corner case where the Kerberos password
- # has expired and a prompt is displayed to enter new password. Ideally,
- # we would want to read from stdout but these are blocked reads. This is
- # a hack to kill the process if it's taking too long!
-
- class Alarm(Exception):
- pass
-
- def signal_handler(signum, frame):
- raise Alarm
- # Set the signal handler and a 1-second alarm
- signal.signal(signal.SIGALRM, signal_handler)
- signal.alarm(1)
- try:
- kinit.wait() # Wait for the child to exit
- signal.alarm(0) # Reset the alarm
- return kinit.returncode # Exit status of child on graceful exit
- except Alarm:
- # Taking too long, kill and return error
- kinit.kill()
- return -1