def test_get_groups_from_username_err(self):
     try:
         ku.get_groups_from_username("Zroot")
     except RuntimeError as err:
         self.assertTrue(err.args[0].startswith("Failure running id -G"))
     else:
         self.fail("Expected RuntimeError")
 def test_get_groups_from_username(self):
     groups = ku.get_groups_from_username("root")
     self.assertTrue("root" in groups)
Example #3
0
    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