Exemplo n.º 1
0
def clouds():
    ''' Looks up auth token key and returns the clouds this user
    has been authenticated against '''

    token_store = TokenStore(memcache.Client(['127.0.0.1:11211']))
    token_id = flask.request.headers["x-auth-token"]
    token_info = token_store.get(str(token_id))
    active_clouds = json.dumps(
            [key for key in token_info if key != "__tukey_internal"])
    print active_clouds
    return active_clouds
Exemplo n.º 2
0
def clouds():
    ''' Looks up auth token key and returns the clouds this user
    has been authenticated against '''

    token_store = TokenStore(memcache.Client(['127.0.0.1:11211']))
    token_id = flask.request.headers["x-auth-token"]
    token_info = token_store.get(str(token_id))
    active_clouds = json.dumps(
        [key for key in token_info if key != "__tukey_internal"])
    print active_clouds
    return active_clouds
Exemplo n.º 3
0
    def __init__(self,
                 cloud_name,
                 auth_token,
                 memcache_client,
                 eucarc_path=None):
        ''' eucarc_path should be a format string that allows for the username
        '''

        self.token_store = TokenStore(memcache_client)

        self.eucarc_path = eucarc_path

        self._keystone = None

        super(KeystoneProxy, self).__init__(cloud_name, auth_token)
Exemplo n.º 4
0
def list_simple_tenant_usage(project_id):

    # TODO: move this to the database
    resources = {
        "cloud": {
            "adler": "OSDC-Adler",
            "tcga": "Bionimbus-PDC",
            "pdc": "Bionimbus-PDC",
            "sullivan": "OSDC-Sullivan",
            "atwood": "atwood",
            "goldberg": "goldberg",
            "cobb": "cobb",
        },
        "hadoop": {name.replace("-", "_").lower(): name for name in ["OCC-Y", "OCC-LVOC-HADOOP", "skidmore"]},
    }

    toks = TokenStore(memcache.Client(["127.0.0.1:11211"]))
    token_info = toks.get(str(flask.g.auth_token))

    username = token_info["__tukey_internal"]["access"]["user"]["username"]

    conn_str = "".join(
        [
            "dbname='",
            local_settings.USAGE_DB_NAME,
            "' user='******' host='",
            local_settings.USAGE_DB_HOST,
            "' password='******' port=",
            str(local_settings.USAGE_DB_PORT),
        ]
    )

    db_connection = psycopg2.connect(conn_str)

    from tukey_middleware.cloud_driver.osdc_euca import OsdcUsage

    start = flask.request.args.get("start")
    stop = flask.request.args.get("end")

    # TODO: instead pass in a connection string
    osdc_usage = OsdcUsage(db_connection, resources)
    tenant_usage = osdc_usage.list_usages(start, stop, str(username))

    return json.dumps({"tenant_usage": tenant_usage})
Exemplo n.º 5
0
def tenant_request():
    ''' Request for just the tenant info. This request assumes that /tokens
    was accessed and created the entry in memcached '''

    try:
        token_id = flask.request.headers["x-auth-token"]
    except KeyError:
        flask.abort(401)

    toks = TokenStore(memcache.Client(['127.0.0.1:11211']))
    token_info = toks.get(str(token_id))

    tenants = {
        "tenants_links": [],
        "tenants": [
           token_info["__tukey_internal"]["access"]["token"]["tenant"]
        ]
    }
    return json.dumps(tenants)
Exemplo n.º 6
0
    def get_cloud_by_id(self, cloud_name, auth_token):
        try:
            toks = TokenStore(memcache.Client(['127.0.0.1:11211']))
            token_info = toks.get(str(auth_token))

            if cloud_name.startswith("cluster"):
                cloud_name = cloud_name[len("cluster"):]
                cloud_info = token_info[cloud_name]
                base_driver = self._initialize_cloud(cloud_info, cloud_name,
                        auth_token)
                return OsdcNovacluster(base_driver)

            elif cloud_name.startswith("login"):
                return self.build_login_driver_by_name(cloud_name, token_info,
                        auth_token)

            elif cloud_name == "all":
                # This will probably only ever be used for generating pubkeys
                # for all clouds
                # For now we assume that is the case
                drivers = []
                for key, value in token_info.items():
                    try:
                        if key != "__tukey_internal":
                            if key.startswith("login"):
                                drivers.append(self.build_login_driver_by_name(
                                        key, token_info, auth_token))
                            elif value.get("instance_keypairs", False):
                                drivers.append(self._initialize_cloud(value,
                                        key, auth_token))
                    except TukeyAuthException:
                        continue

                return AllKeypairsDriver(drivers)

            else:
                cloud_info = token_info[cloud_name]
        except Exception as exc:
            self.logger.info("Accessing cloud %s without auth_token %s",
                    cloud_name, exc.message)
            cloud_info = self.settings[cloud_name]

        return self._initialize_cloud(cloud_info, cloud_name, auth_token)
Exemplo n.º 7
0
def list_simple_tenant_usage(project_id):

    #TODO: move this to the database
    resources = {
        'cloud': {
            'adler': 'OSDC-Adler',
            'tcga': 'Bionimbus-PDC',
            'pdc': 'Bionimbus-PDC',
            'sullivan': 'OSDC-Sullivan',
            'atwood': 'atwood',
            'goldberg': 'goldberg',
            'cobb': 'cobb'
        },
        'hadoop': {
            name.replace('-','_').lower(): name for name in [
                'OCC-Y', 'OCC-LVOC-HADOOP', 'skidmore']
        }
    }

    toks = TokenStore(memcache.Client(['127.0.0.1:11211']))
    token_info = toks.get(str(flask.g.auth_token))

    username = token_info["__tukey_internal"]["access"]["user"]["username"]

    conn_str = "".join(["dbname='", local_settings.USAGE_DB_NAME, "' user='******' host='",
            local_settings.USAGE_DB_HOST, "' password='******' port=",
            str(local_settings.USAGE_DB_PORT)])

    db_connection = psycopg2.connect(conn_str)

    from tukey_middleware.cloud_driver.osdc_euca import OsdcUsage

    start = flask.request.args.get('start')
    stop = flask.request.args.get('end')

    #TODO: instead pass in a connection string
    osdc_usage = OsdcUsage(db_connection, resources)
    tenant_usage = osdc_usage.list_usages(start, stop, str(username))

    return json.dumps({"tenant_usage": tenant_usage})
Exemplo n.º 8
0
    def all_clouds(self, auth_token, client_format=None):
        ''' Return list of cloud_driver objects settings is a dictionary of
        cloud names and their drivers and parameters '''
        self.client_format = client_format
        clouds = []

        toks = TokenStore(memcache.Client(['127.0.0.1:11211']))
        token_info = toks.get(str(auth_token))

        for name, cloud in [(n, c) for n, c in token_info.items()
                if n != '__tukey_internal' and not n.startswith("login")]:
            try:
                driver_instance = self._initialize_cloud(cloud, name,
                        auth_token)
            except TukeyAuthException:
                continue

            clouds.append(driver_instance)
            clouds.append(create_login_driver(name, driver_instance,
                    token_info["login" + name]))

        return clouds
Exemplo n.º 9
0
def token_request():
    ''' Intercept a token request and use that to talk to multiple clouds
    based on values stored in the database.

    request data format will be:

    {"auth": {"passwordCredentials": {
        "password": "******",
        "username": "******"
    }}}

    tukeyPassword is a password shared between the middleware and the portal to
    prevent anyone from talking to the middleware and impersonating users.

    method can be shibboleth or openid.
    identifier is looked up in the tukey auth db which stores users openstack
    credentials. Those credentials are used to talk to the Keystone service
    for each cloud. The auth tokens from each keystone request are stored in
    memcached with one of the tokens used as the key and returned back to
    Horizon. '''

    token_store = TokenStore(memcache.Client(['127.0.0.1:11211']))
    logger = utils.get_logger()

    try:
        token_id = flask.request.headers["x-auth-token"]
        token_info = token_store.get(str(token_id))
        return json.dumps(token_info["__tukey_internal"])
    except KeyError:
        pass

    pw_creds = json.loads(flask.request.data)["auth"]["passwordCredentials"]

    # string equality in Python is probably a side-channel vector
    if pw_creds["password"] != settings["shared_password"]:
        return ("Wrong credentials", 401)

    method, userid = pw_creds["username"].split()

    user_info_query = '''
        select username, password, cloud_name, display_name, auth_url, login_url,
            instance_keypairs.cloud_id
        from
        login join
        login_enabled on login.id = login_enabled.login_id join
        login_identifier on login.userid = login_identifier.userid join
        login_identifier_enabled on login_identifier.id =
            login_identifier_enabled.login_identifier_id join
        login_method on login_method.method_id = login_identifier.method_id
            join
        cloud on cloud.cloud_id = login.cloud_id
            left outer join
        instance_keypairs on instance_keypairs.cloud_id = cloud.cloud_id
        where login_method.method_name='%(method)s'
            and LOWER(login_identifier.identifier)=LOWER('%(id)s');
    ''' % {"method": method, "id": userid}

    engine = sqlalchemy.create_engine(settings["auth_db_str"])
    with engine.begin() as connection:
        results = connection.execute(sqlalchemy.text(user_info_query))

    roles = []
    info_by_cloud = {}
    tenant = None

    endpoints = {}

    for (_username, password, cloud, display_name, auth_url, login_url,
            instance_keypairs) in results:
        if auth_url:
            try:
                try:
                    ksc = keystone_client(auth_url=auth_url, username=_username,
                        password=password)
                except keystoneclient.apiclient.exceptions.Unauthorized:
                    # this should be a valid username so let Horizon know
                    logger.info(("Cloud %s Keystone at %s ",
                            "rejected username password: %s %s"), cloud,
                            auth_url, _username, password)
                    # this is probably not the best or clearest, just different
                    flask.abort(403)

                tenants = [t for t in ksc.tenants.list() if t.enabled]

                if len(tenants) < 1:
                    logger.info("Cloud %s username: %s has no tenants", cloud,
                            _username)
                    continue

                for tenant in tenants:
                    if tenant.name == _username:
                        break

                token_response = ksc.get_raw_token_from_identity_service(
                        auth_url, username=_username, password=password,
                        tenant_name=tenant.name)

                try:
                    # this should work if keystoneclient version <= 0.6.0
                    response, raw_token = token_response
                    response_status = response.status_code
                except ValueError:
                    # this should work if keystoneclient version >= 0.7.0
                    raw_token = token_response
                    response_status = 200

                # handle changes between 0.6.0 and 0.7.0
                if "access" not in raw_token:
                    raw_token = {"access": raw_token}

                if response_status != 200:
                    logger.info(("Cloud %s Keystone at %s ",
                            "rejected username: %s with status code: %s"),
                            cloud, auth_url, _username, response_status)
                    flask.abort(403)

                # add enpoints
                for endpoint in raw_token["access"]["serviceCatalog"]:
                    endpoints[endpoint["type"]] = endpoint["name"]

                token_id = ksc.auth_token
                user_id = ksc.user_id
                username = _username
                raw_token["cloud"] = display_name
                if instance_keypairs:
                    raw_token["instance_keypairs"] = True
                info_by_cloud[cloud] = raw_token
                info_by_cloud["login" + cloud] = login_url

                roles += raw_token["access"]["user"]["roles"]
                raw_token["cloud"] = display_name
            except AuthorizationFailure:
                logger.info("Keystone failed for %s", cloud)
        else:
            info_by_cloud[cloud] = {"username": _username,
                    "cloud": display_name,
                    "instance_keypairs": True if instance_keypairs else False}
            info_by_cloud["login" + cloud] = login_url

    if tenant is None:
        logger.info("Login failed for %s using method %s", userid, method)
        flask.abort(401)

    region = "RegionOne"
    host, port = "localhost", LOCAL_PORT

    allowed_services = ['compute', 'image', 'volume', 'object-store']

    # glance assumes that it is at /v1 so we will give it that
    #service_paths = {k: K for k in allowed_services}
    #service_paths["image"] = "v1"

    services = [("http://%s:%s/%s/%s" % (host, port, service, tenant.id),
                    service, service_name)
            for service, service_name in endpoints.items()
                if service in allowed_services]

    services += [("http://%s:%s/v2.0" % (host, port), "identity", "keystone")]

    catalog = {
        "access": {
            "token": {
                "expires": expiration(43200),
                "id": token_id,
                "tenant": format_tenant(tenant.name, tenant.id)
            },
            "serviceCatalog": [
                service_catalog_entry(url, region, url, url, service_type, name)
                    for url, service_type, name in services] + [
                service_catalog_entry(
                        "http://%s:%s/services/Admin" % (host, port), region,
                        "http://%s:%s/services/Cloud" % (host, port),
                        "http://%s:%s/services/Cloud" % (host, port), "ec2",
                        "ec2")],
            "user": {
                "username": username,
                "roles_links": [],
                "id": user_id,
                "roles": roles,
                "name": username
            }},
            "path": "", "host": host, "port": port}

    info_by_cloud["__tukey_internal"] = catalog

    # TODO:
    # see what the shortest expiration is in the set of expirations
    # then set the returned expiration to that and make sure that
    # the memcache expiration is greater than that but has a value so
    # that memcached entries don't fill everything up

    token_store.set(str(token_id), info_by_cloud, 172800)
    logger.info("Login succeeded for %s using method %s" % (userid, method))

    return json.dumps(catalog)
Exemplo n.º 10
0
class KeystoneProxy(Auth):
    ''' Used to talk to the old tukey-middleware authentication proxy that
    uses memcached to keep track of user credentials '''
    def __init__(self,
                 cloud_name,
                 auth_token,
                 memcache_client,
                 eucarc_path=None):
        ''' eucarc_path should be a format string that allows for the username
        '''

        self.token_store = TokenStore(memcache_client)

        self.eucarc_path = eucarc_path

        self._keystone = None

        super(KeystoneProxy, self).__init__(cloud_name, auth_token)

    def init_auth(self, cloud_name, auth_token):
        ''' The KeystoneProxy uses the dictionary self.values to answer all
        the future auth questions '''

        try:
            values = self.token_store.get(str(auth_token))
            if values == None:
                self.values = {}
            else:
                if cloud_name in values:
                    # store the distinguished info
                    self._tukey_internal = values["__tukey_internal"]
                    self.values = values[cloud_name]
                else:
                    self.values = {}

        except memcache.Client.MemcachedKeyNoneError:
            self.values = {}

        # ec2 clouds
        if "username" in self.values.keys():
            self._username = self.values["username"]
            self.ec2 = Ec2rcHandler(self.eucarc_path, cloud_name,
                                    self._username)

        # openstack clouds
        elif "access" in self.values.keys():
            self._username = self.values["access"]["user"]["username"]

    @raise_unauthorized
    def username(self):
        return self._username

    @raise_unauthorized
    def ec2_access_key(self):
        return self.ec2["EC2_ACCESS_KEY"]

    @raise_unauthorized
    def ec2_secret_key(self):
        return self.ec2["EC2_SECRET_KEY"]

    def get_value(self, key):
        if key in self.values:
            return self.values[key]
        return self.ec2[key]

    @raise_unauthorized
    def host(self):
        return self.get_value("host")

    @raise_unauthorized
    def port(self):
        return self.get_value("port")

    @raise_unauthorized
    def path(self):
        return self.get_value("path")

    @raise_unauthorized
    def auth_token(self):
        return self.values["access"]["token"]["id"]

    @raise_unauthorized
    def tenant_id(self):
        return self.values["access"]["token"]["tenant"]["id"]

    @raise_unauthorized
    def tukey_tenant_id(self):
        return self._tukey_internal["access"]["token"]["tenant"]["id"]

    @property
    def auth_url(self):
        '''Format auth url, Need to support https!'''
        return self.get_endpoint("identity")

    @property
    def keystone(self):
        ''' Keystone client '''
        if self._keystone is None:
            self._keystone = keystone_client(auth_url=self.auth_url,
                                             tenant_id=self.tenant_id(),
                                             token=self.auth_token())
        return self._keystone

    @raise_unauthorized
    def tenant_name(self):
        ''' Fetch project name from keystone client'''
        return self.keystone.project_name

    def get_endpoint(self, name):
        ''' Return the internal URL of endpoint with name 'name' '''
        for service in self.values["access"]["serviceCatalog"]:
            if service["type"] == name:
                return service["endpoints"][0]["publicURL"]

    @staticmethod
    def handle_parameters(params):

        try:
            ec2path = params["eucarc_path"]
        except KeyError:
            ec2path = None

        mc_class = utils.get_class(params["memcache_client"]["class"])
        mc_params = params["memcache_client"]["params"]
        mc = mc_class(mc_params[0], mc_params[1])

        logger = utils.get_logger()
        logger.debug(mc)
        logger.debug("doing lambda now ")

        return lambda cloud, token: KeystoneProxy(
            cloud, token, mc, eucarc_path=ec2path)