Ejemplo n.º 1
0
 def _require_domain_xor_project(self, domain, project):
     if domain and project:
         msg = _('Specify either a domain or project, not both')
         raise exceptions.ValidationError(msg)
     elif not (domain or project):
         msg = _('Must specify either a domain or project')
         raise exceptions.ValidationError(msg)
Ejemplo n.º 2
0
 def _require_user_xor_group(self, user, group):
     if user and group:
         msg = _('Specify either a user or group, not both')
         raise exceptions.ValidationError(msg)
     elif not (user or group):
         msg = _('Must specify either a user or group')
         raise exceptions.ValidationError(msg)
Ejemplo n.º 3
0
def _process_communicate_handle_oserror(process, data, files):
    """Wrapper around process.communicate that checks for OSError."""
    try:
        output, err = process.communicate(data)
    except OSError as e:
        if e.errno != errno.EPIPE:
            raise
        # OSError with EPIPE only occurs with old Python 2.7.x versions
        # http://bugs.python.org/issue10963

        # The quick exit is typically caused by the openssl command not being
        # able to read an input file, so check ourselves if can't read a file.
        retcode, err = _check_files_accessible(files)
        if process.stderr:
            msg = process.stderr.read()
            if isinstance(msg, six.binary_type):
                msg = msg.decode("utf-8")
            if err:
                err = _(
                    "Hit OSError in "
                    "_process_communicate_handle_oserror(): "
                    "%(stderr)s\nLikely due to %(file)s: %(error)s"
                ) % {"stderr": msg, "file": err[0], "error": err[1]}
            else:
                err = _("Hit OSError in " "_process_communicate_handle_oserror(): %s") % msg

        output = ""
    else:
        retcode = process.poll()
        if err is not None:
            if isinstance(err, six.binary_type):
                err = err.decode("utf-8")

    return output, err, retcode
Ejemplo n.º 4
0
    def generate(self, credentials):
        """Generate auth string according to what SignatureVersion is given."""
        signature_version = credentials['params'].get('SignatureVersion')
        if signature_version == '0':
            return self._calc_signature_0(credentials['params'])
        if signature_version == '1':
            return self._calc_signature_1(credentials['params'])
        if signature_version == '2':
            return self._calc_signature_2(credentials['params'],
                                          credentials['verb'],
                                          credentials['host'],
                                          credentials['path'])
        if self._v4_creds(credentials):
            return self._calc_signature_4(credentials['params'],
                                          credentials['verb'],
                                          credentials['host'],
                                          credentials['path'],
                                          credentials['headers'],
                                          credentials['body_hash'])

        if signature_version is not None:
            raise Exception(_('Unknown signature version: %s') %
                            signature_version)
        else:
            raise Exception(_('Unexpected signature format'))
Ejemplo n.º 5
0
    def load_from_argparse_arguments(cls, namespace, **kwargs):
        token = kwargs.get('token') or namespace.os_token
        endpoint = kwargs.get('endpoint') or namespace.os_endpoint
        auth_url = kwargs.get('auth_url') or namespace.os_auth_url

        if token and not endpoint:
            # if a user provides a token then they must also provide an
            # endpoint because we aren't fetching a token to get a catalog from
            msg = _('A service URL must be provided with a token')
            raise exc.CommandError(msg)
        elif (not token) and (not auth_url):
            # if you don't provide a token you are going to provide at least an
            # auth_url with which to authenticate.
            raise exc.CommandError(_('Expecting an auth URL via either '
                                     '--os-auth-url or env[OS_AUTH_URL]'))

        plugin = super(DefaultCLI, cls).load_from_argparse_arguments(namespace,
                                                                     **kwargs)

        if (not token) and (not plugin._password):
            # we do this after the load so that the base plugin has an
            # opportunity to prompt the user for a password
            raise exc.CommandError(_('Expecting a password provided via '
                                     'either --os-password, env[OS_PASSWORD], '
                                     'or prompted response'))

        return plugin
Ejemplo n.º 6
0
def do_discover(cs, args):
    """Discover Keystone servers, supported API versions and extensions.
    """
    if cs.endpoint:
        versions = cs.discover(cs.endpoint)
    elif cs.auth_url:
        versions = cs.discover(cs.auth_url)
    else:
        versions = cs.discover()
    if versions:
        if 'message' in versions:
            print(versions['message'])
        for key, version in six.iteritems(versions):
            if key != 'message':
                print(_("    - supports version %(id)s (%(status)s) here "
                        "%(url)s") %
                      version)
                extensions = cs.discover_extensions(version['url'])
                if extensions:
                    for key, extension in six.iteritems(extensions):
                        if key != 'message':
                            print(_("        - and %(key)s: %(extension)s") %
                                  {'key': key, 'extension': extension})
    else:
        print(_("No Keystone-compatible endpoint found"))
Ejemplo n.º 7
0
def do_endpoint_delete(kc, args):
    """Delete a service endpoint."""
    try:
        kc.endpoints.delete(args.id)
        print(_('Endpoint has been deleted.'))
    except Exception:
        print(_('Unable to delete endpoint.'))
Ejemplo n.º 8
0
    def process_token(self, region_name=None):
        """Extract and process information from the new auth_ref.

        And set the relevant authentication information.
        """
        # if we got a response without a service catalog, set the local
        # list of tenants for introspection, and leave to client user
        # to determine what to do. Otherwise, load up the service catalog
        if self.auth_ref.project_scoped:
            if not self.auth_ref.tenant_id:
                raise exceptions.AuthorizationFailure(
                    _("Token didn't provide tenant_id"))
            self._process_management_url(region_name)
            self.project_name = self.auth_ref.tenant_name
            self.project_id = self.auth_ref.tenant_id

        if not self.auth_ref.user_id:
            raise exceptions.AuthorizationFailure(
                _("Token didn't provide user_id"))

        self.user_id = self.auth_ref.user_id

        self.auth_domain_id = self.auth_ref.domain_id
        self.auth_tenant_id = self.auth_ref.tenant_id
        self.auth_user_id = self.auth_ref.user_id
    def get_raw_token_from_identity_service(self, auth_url, username=None,
                                            api_key=None, tenant_id=None,
                                            password=None, project_id=None,
                                            **kwargs):
        """Authenticate against the v2 Identity API using an API key.

        :returns: access.AccessInfo if authentication was successful.
        :raises keystoneclient.AuthorizationFailure: if unable to authenticate
            or validate the existing authorization token
        """
        if api_key is None:
            api_key = self._api_key

        if password is None:
            password = self.password

        try:
            if auth_url is None:
                raise ValueError(_("Cannot authenticate without an auth_url"))

            plugin = self.get_auth_plugin(auth_url, api_key, username,
                                          password, project_id, tenant_id)

            return plugin.get_auth_ref(self.session)
        except (AuthorizationFailure, Unauthorized) as exc:
            LOG.debug("Authorization Failed.", exc_info=exc)
            raise
        except EndpointNotFound as exc:
            msg = _(
                'There was no suitable authentication url for this request')
            six.raise_from(AuthorizationFailure(msg), exc)
        except Exception as exc:
            msg = _("Authorization Failed: {0}".format(exc))
            six.raise_from(AuthorizationFailure(msg), exc)
Ejemplo n.º 10
0
    def get_token(self, auth=None):
        """Return a token as provided by the auth plugin.

        :param auth: The auth plugin to use for token. Overrides the plugin
                     on the session. (optional)
        :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin`

        :raises keystoneclient.exceptions.AuthorizationFailure: if a new token
                                                                fetch fails.
        :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not
                                                             available.

        :returns: A valid token.
        :rtype: string
        """
        if not auth:
            auth = self.auth

        if not auth:
            raise exceptions.MissingAuthPlugin(_("Token Required"))

        try:
            return auth.get_token(self)
        except exceptions.HttpError as exc:
            raise exceptions.AuthorizationFailure(
                _("Authentication failure: %s") % exc)
Ejemplo n.º 11
0
def do_ec2_credentials_delete(kc, args):
    """Delete EC2-compatible credentials."""
    if not args.user_id:
        # use the authenticated user id as a default
        args.user_id = kc.auth_user_id
    try:
        kc.ec2.delete(args.user_id, args.access)
        print(_('Credential has been deleted.'))
    except Exception as e:
        print(_('Unable to delete credential: %s') % e)
Ejemplo n.º 12
0
    def get_auth_ref(self, session, **kwargs):
        headers = {'Accept': 'application/json'}
        body = {'auth': {'identity': {}}}
        ident = body['auth']['identity']
        rkwargs = {}

        for method in self.auth_methods:
            name, auth_data = method.get_auth_data(session,
                                                   self,
                                                   headers,
                                                   request_kwargs=rkwargs)
            ident.setdefault('methods', []).append(name)
            ident[name] = auth_data

        if not ident:
            raise exceptions.AuthorizationFailure(
                _('Authentication method required (e.g. password)'))

        mutual_exclusion = [bool(self.domain_id or self.domain_name),
                            bool(self.project_id or self.project_name),
                            bool(self.trust_id)]

        if sum(mutual_exclusion) > 1:
            raise exceptions.AuthorizationFailure(
                _('Authentication cannot be scoped to multiple targets. Pick '
                  'one of: project, domain or trust'))

        if self.domain_id:
            body['auth']['scope'] = {'domain': {'id': self.domain_id}}
        elif self.domain_name:
            body['auth']['scope'] = {'domain': {'name': self.domain_name}}
        elif self.project_id:
            body['auth']['scope'] = {'project': {'id': self.project_id}}
        elif self.project_name:
            scope = body['auth']['scope'] = {'project': {}}
            scope['project']['name'] = self.project_name

            if self.project_domain_id:
                scope['project']['domain'] = {'id': self.project_domain_id}
            elif self.project_domain_name:
                scope['project']['domain'] = {'name': self.project_domain_name}
        elif self.trust_id:
            body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}}

        _logger.debug('Making authentication request to %s', self.token_url)
        resp = session.post(self.token_url, json=body, headers=headers,
                            authenticated=False, log=False, **rkwargs)

        try:
            resp_data = resp.json()['token']
        except (KeyError, ValueError):
            raise exceptions.InvalidResponse(response=resp)

        return access.AccessInfoV3(resp.headers['X-Subject-Token'],
                                   **resp_data)
Ejemplo n.º 13
0
def _positive_non_zero_float(argument_value):
    if argument_value is None:
        return None
    try:
        value = float(argument_value)
    except ValueError:
        msg = _("%s must be a float") % argument_value
        raise argparse.ArgumentTypeError(msg)
    if value <= 0:
        msg = _("%s must be greater than 0") % argument_value
        raise argparse.ArgumentTypeError(msg)
    return value
Ejemplo n.º 14
0
    def __init__(self, api_key=None, **kwargs):
        """Initialize a new client for the Keystone v2.0 API using an API
        key or password."""

        if not any((api_key, kwargs.get('password'))):
            raise ValueError(_(
                "Cannot authenticate without an api_key or password"))

        if kwargs.get('username') is None:
            raise ValueError(_("Cannot authenticate without a username"))

        self._api_key = api_key

        super(Client, self).__init__(**kwargs)
Ejemplo n.º 15
0
    def update_password(self, old_password, new_password):
        """Update the password for the user the token belongs to."""
        if not (old_password and new_password):
            msg = _("Specify both the current password and a new password")
            raise exceptions.ValidationError(msg)

        if old_password == new_password:
            msg = _("Old password and new password must be different.")
            raise exceptions.ValidationError(msg)

        params = {"user": {"password": new_password, "original_password": old_password}}

        base_url = "/users/%s/password" % self.client.user_id

        return self._update(base_url, params, method="POST", log=False)
Ejemplo n.º 16
0
def _check_files_accessible(files):
    err = None
    retcode = -1
    try:
        for try_file in files:
            with open(try_file, 'r'):
                pass
    except IOError as e:
        # Catching IOError means there is an issue with
        # the given file.
        err = _('Hit OSError in _process_communicate_handle_oserror()\n'
                'Likely due to %(file)s: %(error)s') % {'file': try_file,
                                                        'error': e.strerror}
        # Emulate openssl behavior, which returns with code 2 when
        # access to a file failed:

        # You can get more from
        # http://www.openssl.org/docs/apps/cms.html#EXIT_CODES
        #
        # $ openssl cms -verify -certfile not_exist_file -CAfile \
        #       not_exist_file -inform PEM -nosmimecap -nodetach \
        #       -nocerts -noattr
        # Error opening certificate file not_exist_file
        retcode = 2

    return retcode, err
Ejemplo n.º 17
0
    def authenticate(self, username=None, tenant_id=None, tenant_name=None,
                     password=None, token=None, return_raw=False):
        if token:
            params = {"auth": {"token": {"id": token}}}
        elif username and password:
            params = {"auth": {"passwordCredentials": {"username": username,
                                                       "password": password}}}
        else:
            raise ValueError(
                _('A username and password or token is required.'))
        if tenant_id:
            params['auth']['tenantId'] = tenant_id
        elif tenant_name:
            params['auth']['tenantName'] = tenant_name

        args = ['/tokens', params, 'access']
        kwargs = {'return_raw': return_raw, 'log': False}

        # NOTE(jamielennox): try doing a regular admin query first. If there is
        # no endpoint that can satisfy the request (eg an unscoped token) then
        # issue it against the auth_url.
        try:
            token_ref = self._post(*args, **kwargs)
        except exceptions.EndpointNotFound:
            kwargs['endpoint_filter'] = {'interface': auth.AUTH_INTERFACE}
            token_ref = self._post(*args, **kwargs)

        return token_ref
Ejemplo n.º 18
0
def get_version_data(session, url, authenticated=None):
    """Retrieve raw version data from a url."""
    headers = {'Accept': 'application/json'}

    resp = session.get(url, headers=headers, authenticated=authenticated)

    try:
        body_resp = resp.json()
    except ValueError:
        pass
    else:
        # In the event of querying a root URL we will get back a list of
        # available versions.
        try:
            return body_resp['versions']['values']
        except (KeyError, TypeError):
            pass

        # Most servers don't have a 'values' element so accept a simple
        # versions dict if available.
        try:
            return body_resp['versions']
        except KeyError:
            pass

        # Otherwise if we query an endpoint like /v2.0 then we will get back
        # just the one available version.
        try:
            return [body_resp['version']]
        except KeyError:
            pass

    err_text = resp.text[:50] + '...' if len(resp.text) > 50 else resp.text
    msg = _('Invalid Response - Bad version data returned: %s') % err_text
    raise exceptions.DiscoveryFailure(msg)
Ejemplo n.º 19
0
    def list(self, fallback_to_auth=False, **kwargs):
        if 'id' in kwargs.keys():
            # Ensure that users are not trying to call things like
            # ``domains.list(id='default')`` when they should have used
            # ``[domains.get(domain_id='default')]`` instead. Keystone supports
            # ``GET /v3/domains/{domain_id}``, not ``GET
            # /v3/domains?id={domain_id}``.
            raise TypeError(
                _("list() got an unexpected keyword argument 'id'. To "
                  "retrieve a single object using a globally unique "
                  "identifier, try using get() instead."))

        url = self.build_url(dict_args_in_out=kwargs)

        try:
            query = self._build_query(kwargs)
            url_query = '%(url)s%(query)s' % {'url': url, 'query': query}
            return self._list(
                url_query,
                self.collection_key)
        except exceptions.EmptyCatalog:
            if fallback_to_auth:
                return self._list(
                    url_query,
                    self.collection_key,
                    endpoint_filter={'interface': auth.AUTH_INTERFACE})
            else:
                raise
Ejemplo n.º 20
0
    def __init__(self, **kwargs):
        for param in self._method_parameters:
            setattr(self, param, kwargs.pop(param, None))

        if kwargs:
            msg = _("Unexpected Attributes: %s") % ", ".join(kwargs.keys())
            raise AttributeError(msg)
Ejemplo n.º 21
0
    def _check_keystone_extensions(self, url):
        """Call Keystone URL and detects the available extensions."""
        try:
            if not url.endswith("/"):
                url += '/'
            resp, body = self._request("%sextensions" % url, "GET",
                                       headers={'Accept':
                                                'application/json'})
            if resp.status_code in (200, 204):  # some cases we get No Content
                if 'extensions' in body and 'values' in body['extensions']:
                    # Parse correct format (per contract)
                    extensions = body['extensions']['values']
                elif 'extensions' in body:
                    # Support incorrect, but prevalent format
                    extensions = body['extensions']
                else:
                    return dict(message=(
                        _('Unrecognized extensions response from %s') % url))

                return dict(self._get_extension_info(e) for e in extensions)
            elif resp.status_code == 305:
                return self._check_keystone_extensions(resp['location'])
            else:
                raise exceptions.from_response(
                    resp, "GET", "%sextensions" % url)
        except Exception:
            _logger.exception('Failed to check keystone extensions.')
Ejemplo n.º 22
0
    def _access_service_provider(self, session):
        """Access protected endpoint and fetch unscoped token.

        After federated authentication workflow a protected endpoint should be
        accessible with the session object. The access is granted basing on the
        cookies stored within the session object. If, for some reason no
        cookies are present (quantity test) it means something went wrong and
        user will not be able to fetch an unscoped token. In that case an
        ``exceptions.AuthorizationFailure` exception is raised and no HTTP call
        is even made.

        :param session : a session object to send out HTTP requests.
        :type session: keystoneclient.session.Session

        :raises keystoneclient.exceptions.AuthorizationFailure: in case session
        object has empty cookie jar.

        """
        if self._cookies(session) is False:
            raise exceptions.AuthorizationFailure(
                _(
                    "Session object doesn't contain a cookie, therefore you are "
                    "not allowed to enter the Identity Provider's protected "
                    "area."
                )
            )
        self.authenticated_response = session.get(self.token_url, authenticated=False)
Ejemplo n.º 23
0
    def __getattr__(self, name):
        try:
            var_name = self.deprecated_session_variables[name]
        except KeyError:
            pass
        else:
            warnings.warn(
                "The %s session variable is deprecated as of the 1.7.0 "
                "release and may be removed in the 2.0.0 release" % name,
                DeprecationWarning,
            )
            return getattr(self.session, var_name or name)

        try:
            var_name = self.deprecated_adapter_variables[name]
        except KeyError:
            pass
        else:
            warnings.warn(
                "The %s adapter variable is deprecated as of the 1.7.0 "
                "release and may be removed in the 2.0.0 release" % name,
                DeprecationWarning,
            )
            return getattr(self._adapter, var_name or name)

        raise AttributeError(_("Unknown Attribute: %s") % name)
Ejemplo n.º 24
0
    def find(self, **kwargs):
        """Find a single item with attributes matching ``**kwargs``."""
        url = self.build_url(dict_args_in_out=kwargs)

        query = self._build_query(kwargs)
        url_query = '%(url)s%(query)s' % {
            'url': url,
            'query': query
        }
        elements = self._list(
            url_query,
            self.collection_key)

        if self.client.include_metadata:
            base_response = elements
            elements = elements.data
            base_response.data = elements[0]

        if not elements:
            msg = _("No %(name)s matching %(kwargs)s.") % {
                'name': self.resource_class.__name__, 'kwargs': kwargs}
            raise ksa_exceptions.NotFound(404, msg)
        elif len(elements) > 1:
            raise ksc_exceptions.NoUniqueMatch
        else:
            return (base_response if self.client.include_metadata
                    else elements[0])
Ejemplo n.º 25
0
 def __getattribute__(self, name):
     """Return error when name is related to oauthlib and not exist."""
     if name in ('access_tokens', 'consumers', 'request_tokens'):
         raise NotImplementedError(
             _('To use %r oauthlib must be installed') % name)
     return super(OAuthManagerOptionalImportProxy,
                  self).__getattribute__(name)
Ejemplo n.º 26
0
    def _check_consumer_urls(self, session, sp_response_consumer_url,
                             idp_sp_response_consumer_url):
        """Check if consumer URLs issued by SP and IdP are equal.

        In the initial SAML2 authn Request issued by a Service Provider
        there is a url called ``consumer url``. A trusted Identity Provider
        should issue identical url. If the URLs are not equal the federated
        authn process should be interrupted and the user should be warned.

        :param session: session object to send out HTTP requests.
        :type session: keystoneclient.session.Session
        :param sp_response_consumer_url: consumer URL issued by a SP
        :type  sp_response_consumer_url: string
        :param idp_sp_response_consumer_url: consumer URL issued by an IdP
        :type idp_sp_response_consumer_url: string

        """
        if sp_response_consumer_url != idp_sp_response_consumer_url:
            # send fault message to the SP, discard the response
            session.post(sp_response_consumer_url, data=self.SOAP_FAULT,
                         headers=self.ECP_SP_SAML2_REQUEST_HEADERS,
                         authenticated=False)

            # prepare error message and raise an exception.
            msg = _("Consumer URLs from Service Provider %(service_provider)s "
                    "%(sp_consumer_url)s and Identity Provider "
                    "%(identity_provider)s %(idp_consumer_url)s are not equal")
            msg = msg % {
                'service_provider': self.token_url,
                'sp_consumer_url': sp_response_consumer_url,
                'identity_provider': self.identity_provider,
                'idp_consumer_url': idp_sp_response_consumer_url
            }

            raise exceptions.ValidationError(msg)
Ejemplo n.º 27
0
    def __init__(self, session=None, authenticated=None, **kwargs):
        if not session:
            warnings.warn(
                'Constructing a Discover instance without using a session is '
                'deprecated as of the 1.7.0 release and may be removed in the '
                '2.0.0 release.', DeprecationWarning)
            session = client_session.Session._construct(kwargs)
        kwargs['session'] = session

        url = None
        endpoint = kwargs.pop('endpoint', None)
        auth_url = kwargs.pop('auth_url', None)

        if endpoint:
            self._use_endpoint = True
            url = endpoint
        elif auth_url:
            self._use_endpoint = False
            url = auth_url

        if not url:
            raise exceptions.DiscoveryFailure(
                _('Not enough information to determine URL. Provide either '
                  'auth_url or endpoint'))

        self._client_kwargs = kwargs
        super(Discover, self).__init__(session, url,
                                       authenticated=authenticated)
Ejemplo n.º 28
0
    def _send_idp_saml2_authn_request(self, session):
        """Present modified SAML2 authn assertion from the Service Provider."""

        self._prepare_idp_saml2_request(self.saml2_authn_request)
        idp_saml2_authn_request = self.saml2_authn_request

        # Currently HTTPBasicAuth method is hardcoded into the plugin
        idp_response = session.post(
            self.identity_provider_url,
            headers={"Content-type": "text/xml"},
            data=etree.tostring(idp_saml2_authn_request),
            requests_auth=(self.username, self.password),
            authenticated=False,
            log=False,
        )

        try:
            self.saml2_idp_authn_response = etree.XML(idp_response.content)
        except etree.XMLSyntaxError as e:
            msg = _("SAML2: Error parsing XML returned " "from Identity Provider, reason: %s") % e
            raise exceptions.AuthorizationFailure(msg)

        idp_response_consumer_url = self.saml2_idp_authn_response.xpath(
            self.ECP_IDP_CONSUMER_URL, namespaces=self.ECP_SAML2_NAMESPACES
        )

        self.idp_response_consumer_url = self._first(idp_response_consumer_url)

        self._check_consumer_urls(session, self.idp_response_consumer_url, self.sp_response_consumer_url)
Ejemplo n.º 29
0
    def update_password(self, old_password, new_password):
        """Update the password for the user the token belongs to."""
        if not (old_password and new_password):
            msg = _('Specify both the current password and a new password')
            raise exceptions.ValidationError(msg)

        if old_password == new_password:
            msg = _('Old password and new password must be different.')
            raise exceptions.ValidationError(msg)

        params = {'user': {'password': new_password,
                           'original_password': old_password}}

        base_url = '/users/%s/password' % self.client.user_id

        return self._update(base_url, params, method='POST', log=False)
Ejemplo n.º 30
0
def normalize_version_number(version):
    """Turn a version representation into a tuple."""

    # trim the v from a 'v2.0' or similar
    try:
        version = version.lstrip('v')
    except AttributeError:
        pass

    # if it's an integer or a numeric as a string then normalize it
    # to a string, this ensures 1 decimal point
    try:
        num = float(version)
    except Exception:
        pass
    else:
        version = str(num)

    # if it's a string (or an integer) from above break it on .
    try:
        return tuple(map(int, version.split('.')))
    except Exception:
        pass

    # last attempt, maybe it's a list or iterable.
    try:
        return tuple(map(int, version))
    except Exception:
        pass

    raise TypeError(_('Invalid version specified: %s') % version)
Ejemplo n.º 31
0
def do_user_password_update(kc, args):
    """Update user password."""
    user = utils.find_resource(kc.users, args.user)
    new_passwd = args.passwd or utils.prompt_for_password()
    if new_passwd is None:
        msg = (_("\nPlease specify password using the --pass option "
                 "or using the prompt"))
        sys.exit(msg)
    kc.users.update_password(user, new_passwd)
Ejemplo n.º 32
0
    def _auth_required(self, auth, msg):
        if not auth:
            auth = self.auth

        if not auth:
            msg_fmt = _('An auth plugin is required to %s')
            raise exceptions.MissingAuthPlugin(msg_fmt % msg)

        return auth
    def add_endpoint_group_to_project(self, project, endpoint_group):
        """Create a project-endpoint_group association.
        PUT /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/projects/{project_id}
        """
        if not (project and endpoint_group):
            raise ValueError(_('project and endpoint_group are required'))

        base_url = self._build_base_url(project=project,
                                        endpoint_group=endpoint_group)
        return super(EndpointGroupFilterManager, self)._put(url=base_url)
    def list_projects_for_endpoint(self, endpoint):
        """List all projects for a given endpoint."""
        if not endpoint:
            raise ValueError(_('endpoint is required'))

        base_url = self._build_base_url(endpoint=endpoint)
        return super(EndpointFilterManager, self)._list(
            base_url,
            projects.ProjectManager.collection_key,
            obj_class=projects.ProjectManager.resource_class)
 def _get_data_blob(self, blob, data):
     # Ref bug #1259461, the <= 0.4.1 keystoneclient calling convention was
     # to pass "data", but the underlying API expects "blob", so
     # support both in the python API for backwards compatibility
     if blob is not None:
         return blob
     elif data is not None:
         return data
     else:
         raise ValueError(_("Credential requires blob to be specified"))
    def list_endpoints_for_project(self, project):
        """List all endpoints for a given project."""
        if not project:
            raise ValueError(_('project is required'))

        base_url = self._build_base_url(project=project)
        return super(EndpointFilterManager, self)._list(
            base_url,
            endpoints.EndpointManager.collection_key,
            obj_class=endpoints.EndpointManager.resource_class)
Ejemplo n.º 37
0
    def list_projects_for_endpoint_group(self, endpoint_group):
        """List all projects associated with a given endpoint group."""
        if not endpoint_group:
            raise ValueError(_('endpoint_group is required'))

        base_url = self._build_group_base_url(endpoint_group=endpoint_group)
        return super(EndpointFilterManager, self)._list(
            base_url,
            projects.ProjectManager.collection_key,
            obj_class=projects.ProjectManager.resource_class)
    def check_endpoint_group_in_project(self, project, endpoint_group):
        """Checks if project-endpoint_group association exist.
        HEAD /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/projects/{project_id}
        """
        if not (project and endpoint_group):
            raise ValueError(_('project and endpoint_group are required'))

        base_url = self._build_base_url(project=project,
                                        endpoint_group=endpoint_group)
        return super(EndpointGroupFilterManager, self)._head(url=base_url)
    def delete_endpoint_group_from_project(self, project, endpoint_group):
        """Remove a project-endpoint_group association.
        DELETE /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/projects/{project_id}
        """
        if not (project and endpoint_group):
            raise ValueError(_('project and endpoint_group are required'))

        base_url = self._build_base_url(project=project,
                                        endpoint_group=endpoint_group)
        return super(EndpointGroupFilterManager, self)._delete(url=base_url)
Ejemplo n.º 40
0
    def list_endpoint_groups_for_project(self, project):
        """List all endpoint groups for a given project."""
        if not project:
            raise ValueError(_('project is required'))

        base_url = self._build_group_base_url(project=project)

        return super(EndpointFilterManager, self)._list(
            base_url,
            'endpoint_groups',
            obj_class=endpoint_groups.EndpointGroupManager.resource_class)
Ejemplo n.º 41
0
def _encoding_for_form(inform):
    if inform == PKI_ASN1_FORM:
        encoding = 'UTF-8'
    elif inform == PKIZ_CMS_FORM:
        encoding = 'hex'
    else:
        raise ValueError(
            _('"inform" must be one of: %s') % ','.join(
                (PKI_ASN1_FORM, PKIZ_CMS_FORM)))

    return encoding
Ejemplo n.º 42
0
    def invalidate(self, auth=None):
        """Invalidate an authentication plugin.

        :param auth: The auth plugin to invalidate. Overrides the plugin on the
                     session. (optional)
        :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin`

        """
        msg = _('An auth plugin is required to validate')
        auth = self._auth_required(auth, msg)
        return auth.invalidate()
Ejemplo n.º 43
0
    def _get_adfs_security_token(self, session):
        """Send ADFS Security token to the ADFS server.

        Store the result in the instance attribute and raise an exception in
        case the response is not valid XML data.

        If a user cannot authenticate due to providing bad credentials, the
        ADFS2.0 server will return a HTTP 500 response and a XML Fault message.
        If ``exceptions.InternalServerError`` is caught, the method tries to
        parse the XML response.
        If parsing is unsuccessful, an ``exceptions.AuthorizationFailure`` is
        raised with a reason from the XML fault. Otherwise an original
        ``exceptions.InternalServerError`` is re-raised.

        :param session : a session object to send out HTTP requests.
        :type session: keystoneclient.session.Session

        :raises keystoneclient.exceptions.AuthorizationFailure: when HTTP
                 response from the ADFS server is not a valid XML ADFS security
                 token.
        :raises keystoneclient.exceptions.InternalServerError: If response
                 status code is HTTP 500 and the response XML cannot be
                 recognized.

        """
        def _get_failure(e):
            xpath = '/s:Envelope/s:Body/s:Fault/s:Code/s:Subcode/s:Value'
            content = e.response.content
            try:
                obj = self.str_to_xml(content).xpath(
                    xpath, namespaces=self.NAMESPACES)
                obj = self._first(obj)
                return obj.text
            # NOTE(marek-denis): etree.Element.xpath() doesn't raise an
            # exception, it just returns an empty list. In that case, _first()
            # will raise IndexError and we should treat it as an indication XML
            # is not valid. exceptions.AuthorizationFailure can be raised from
            # str_to_xml(), however since server returned HTTP 500 we should
            # re-raise exceptions.InternalServerError.
            except (IndexError, exceptions.AuthorizationFailure):
                raise e

        request_security_token = self.xml_to_str(self.prepared_request)
        try:
            response = session.post(url=self.identity_provider_url,
                                    headers=self.HEADER_SOAP,
                                    data=request_security_token,
                                    authenticated=False)
        except exceptions.InternalServerError as e:
            reason = _get_failure(e)
            raise exceptions.AuthorizationFailure(reason)
        msg = _("Error parsing XML returned from "
                "the ADFS Identity Provider, reason: %s")
        self.adfs_token = self.str_to_xml(response.content, msg)
Ejemplo n.º 44
0
    def factory(cls,
                resp=None,
                body=None,
                region_name=None,
                auth_token=None,
                **kwargs):
        """Factory function to create a new AccessInfo object.

        Create AccessInfo object given a successful auth response & body
        or a user-provided dict.

        .. warning::

            Use of the region_name argument is deprecated as of the 1.7.0
            release and may be removed in the 2.0.0 release.

        """

        if region_name:
            warnings.warn(
                'Use of the region_name argument is deprecated as of the '
                '1.7.0 release and may be removed in the 2.0.0 release.',
                DeprecationWarning)

        auth_ref = None

        if body is not None or len(kwargs):
            if AccessInfoV3.is_valid(body, **kwargs):
                if resp and not auth_token:
                    auth_token = resp.headers['X-Subject-Token']
                # NOTE(jamielennox): these return AccessInfo because they
                # already have auth_token installed on them.
                if body:
                    if region_name:
                        body['token']['region_name'] = region_name
                    return AccessInfoV3(auth_token, **body['token'])
                else:
                    return AccessInfoV3(auth_token, **kwargs)
            elif AccessInfoV2.is_valid(body, **kwargs):
                if body:
                    if region_name:
                        body['access']['region_name'] = region_name
                    auth_ref = AccessInfoV2(**body['access'])
                else:
                    auth_ref = AccessInfoV2(**kwargs)
            else:
                raise NotImplementedError(_('Unrecognized auth response'))
        else:
            auth_ref = AccessInfoV2(**kwargs)

        if auth_token:
            auth_ref.auth_token = auth_token

        return auth_ref
Ejemplo n.º 45
0
 def _enforce_mutually_exclusive_group(self, system, domain, project):
     if not system:
         if domain and project:
             msg = _('Specify either a domain or project, not both')
             raise exceptions.ValidationError(msg)
         elif not (domain or project):
             msg = _('Must specify either system, domain, or project')
             raise exceptions.ValidationError(msg)
     elif system:
         if domain and project:
             msg = _(
                 'Specify either system, domain, or project, not all three.'
             )
             raise exceptions.ValidationError(msg)
         if domain:
             msg = _('Specify either system or a domain, not both')
             raise exceptions.ValidationError(msg)
         if project:
             msg = _('Specify either a system or project, not both')
             raise exceptions.ValidationError(msg)
Ejemplo n.º 46
0
    def update_password(self, old_password, new_password):
        """Update the password for the user the token belongs to."""
        if not (old_password and new_password):
            msg = _('Specify both the current password and a new password')
            raise exceptions.ValidationError(msg)

        if old_password == new_password:
            msg = _('Old password and new password must be different.')
            raise exceptions.ValidationError(msg)

        params = {
            'user': {
                'password': new_password,
                'original_password': old_password
            }
        }

        base_url = '/users/%s/password' % self.client.user_id

        return self._update(base_url, params, method='POST', log=False)
Ejemplo n.º 47
0
def do_user_update(kc, args):
    """Update user's name, email, and enabled status."""
    kwargs = {}
    if args.name:
        kwargs['name'] = args.name
    if args.email is not None:
        kwargs['email'] = args.email
    if args.enabled:
        kwargs['enabled'] = strutils.bool_from_string(args.enabled)

    if not len(kwargs):
        print(_("User not updated, no arguments present."))
        return

    user = utils.find_resource(kc.users, args.user)
    try:
        kc.users.update(user, **kwargs)
        print(_('User has been updated.'))
    except Exception as e:
        print(_('Unable to update user: %s') % e)
Ejemplo n.º 48
0
    def get_auth_connection_params(self, auth=None, **kwargs):
        """Return auth connection params as provided by the auth plugin.

        An auth plugin may specify connection parameters to the request like
        providing a client certificate for communication.

        We restrict the values that may be returned from this function to
        prevent an auth plugin overriding values unrelated to connection
        parameters. The values that are currently accepted are:

        - `cert`: a path to a client certificate, or tuple of client
          certificate and key pair that are used with this request.
        - `verify`: a boolean value to indicate verifying SSL certificates
          against the system CAs or a path to a CA file to verify with.

        These values are passed to the requests library and further information
        on accepted values may be found there.

        :param auth: The auth plugin to use for tokens. Overrides the plugin
                     on the session. (optional)
        :type auth: keystoneclient.auth.base.BaseAuthPlugin

        :raises keystoneclient.exceptions.AuthorizationFailure: if a new token
                                                                fetch fails.
        :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not
                                                             available.
        :raises keystoneclient.exceptions.UnsupportedParameters: if the plugin
            returns a parameter that is not supported by this session.

        :returns: Authentication headers or None for failure.
        :rtype: dict
        """
        msg = _('An auth plugin is required to fetch connection params')
        auth = self._auth_required(auth, msg)
        params = auth.get_connection_params(self, **kwargs)

        # NOTE(jamielennox): There needs to be some consensus on what
        # parameters are allowed to be modified by the auth plugin here.
        # Ideally I think it would be only the send() parts of the request
        # flow. For now lets just allow certain elements.
        params_copy = params.copy()

        for arg in ('cert', 'verify'):
            try:
                kwargs[arg] = params_copy.pop(arg)
            except KeyError:  # nosec(cjschaef): we are brute force
                # identifying and removing values in params_copy
                pass

        if params_copy:
            raise exceptions.UnsupportedParameters(list(params_copy))

        return params
Ejemplo n.º 49
0
    def _calculate_version(self, version, unstable):
        version_data = None

        if version:
            version_data = self.data_for(version)
        else:
            # if no version specified pick the latest one
            all_versions = self.version_data(unstable=unstable)
            if all_versions:
                version_data = all_versions[-1]

        if not version_data:
            msg = _('Could not find a suitable endpoint')

            if version:
                msg = _('Could not find a suitable endpoint for client '
                        'version: %s') % str(version)

            raise exceptions.VersionNotAvailable(msg)

        return version_data
Ejemplo n.º 50
0
    def _act_on_policy_association_for_service(self, policy, service, action):
        if not (policy and service):
            raise ValueError(_('policy and service are required'))

        policy_id = base.getid(policy)
        service_id = base.getid(service)
        url = ('/policies/%(policy_id)s/%(ext_name)s'
               '/services/%(service_id)s') % {
                   'policy_id': policy_id,
                   'ext_name': self.OS_EP_POLICY_EXT,
                   'service_id': service_id
               }
        return action(url=url)
    def list_endpoint_groups_for_project(self, project):
        """List all endpoints for a given project.
        GET /OS-EP-FILTER/projects/{project_id}/endpoint_groups

        """
        if not project:
            raise ValueError(_('project is required'))

        base_url = self._build_base_url(project=project)
        return super(EndpointGroupFilterManager, self)._list(
            base_url,
            self.collection_key,
            obj_class=self.resource_class)
Ejemplo n.º 52
0
def _process_communicate_handle_oserror(process, data, files):
    """Wrapper around process.communicate that checks for OSError."""

    try:
        output, err = process.communicate(data)
    except OSError as e:
        if e.errno != errno.EPIPE:
            raise
        # OSError with EPIPE only occurs with old Python 2.7.x versions
        # http://bugs.python.org/issue10963

        # The quick exit is typically caused by the openssl command not being
        # able to read an input file, so check ourselves if can't read a file.
        retcode, err = _check_files_accessible(files)
        if process.stderr:
            msg = process.stderr.read()
            if isinstance(msg, six.binary_type):
                msg = msg.decode('utf-8')
            if err:
                err = (_('Hit OSError in '
                         '_process_communicate_handle_oserror(): '
                         '%(stderr)s\nLikely due to %(file)s: %(error)s') % {
                             'stderr': msg,
                             'file': err[0],
                             'error': err[1]
                         })
            else:
                err = (_('Hit OSError in '
                         '_process_communicate_handle_oserror(): %s') % msg)

        output = ''
    else:
        retcode = process.poll()
        if err is not None:
            if isinstance(err, six.binary_type):
                err = err.decode('utf-8')

    return output, err, retcode
Ejemplo n.º 53
0
    def get_raw_token_from_identity_service(self,
                                            auth_url,
                                            username=None,
                                            api_key=None,
                                            tenant_id=None,
                                            password=None,
                                            project_id=None,
                                            **kwargs):
        """Authenticate against the v2 Identity API using an API key.

        :returns: access.AccessInfo if authentication was successful.
        :raises keystoneclient.AuthorizationFailure: if unable to authenticate
            or validate the existing authorization token
        """
        if api_key is None:
            api_key = self._api_key

        if password is None:
            password = self.password

        try:
            if auth_url is None:
                raise ValueError(_("Cannot authenticate without an auth_url"))

            plugin = self.get_auth_plugin(auth_url, api_key, username,
                                          password, project_id, tenant_id)

            return plugin.get_auth_ref(self.session)
        except (AuthorizationFailure, Unauthorized) as exc:
            LOG.debug("Authorization Failed.", exc_info=exc)
            raise
        except EndpointNotFound as exc:
            msg = _(
                'There was no suitable authentication url for this request')
            six.raise_from(AuthorizationFailure(msg), exc)
        except Exception as exc:
            msg = _("Authorization Failed: {0}".format(exc))
            six.raise_from(AuthorizationFailure(msg), exc)
Ejemplo n.º 54
0
    def _act_on_policy_association_for_endpoint(self, policy, endpoint,
                                                action):
        if not (policy and endpoint):
            raise ValueError(_('policy and endpoint are required'))

        policy_id = base.getid(policy)
        endpoint_id = base.getid(endpoint)
        url = ('/policies/%(policy_id)s/%(ext_name)s'
               '/endpoints/%(endpoint_id)s') % {
                   'policy_id': policy_id,
                   'ext_name': self.OS_EP_POLICY_EXT,
                   'endpoint_id': endpoint_id
               }
        return action(url=url)
Ejemplo n.º 55
0
 def _update(self, url, body=None, response_key=None, method="PUT",
             **kwargs):
     methods = {"PUT": self.client.put,
                "POST": self.client.post,
                "PATCH": self.client.patch}
     try:
         resp, body = methods[method](url, body=body,
                                      **kwargs)
     except KeyError:
         raise exceptions.ClientException(_("Invalid update method: %s")
                                          % method)
     # PUT requests may not return a body
     if body:
         return self.resource_class(self, body[response_key])
Ejemplo n.º 56
0
def require_service_catalog(f):
    msg = _('Configuration error: Client configured to run without a service '
            'catalog. Run the client using --os-auth-url or OS_AUTH_URL, '
            'instead of --os-endpoint or OS_SERVICE_ENDPOINT, for example.')

    def wrapped(kc, args):
        if not kc.has_service_catalog():
            raise Exception(msg)
        return f(kc, args)

    # Change __doc__ attribute back to origin function's __doc__
    wrapped.__doc__ = f.__doc__

    return wrapped
Ejemplo n.º 57
0
    def get_auth_plugin(self, auth_url, api_key, username, password,
                        project_id, tenant_id):
        if api_key is not None:
            return ApiKeyAuth(auth_url,
                              api_key,
                              username=username or self.username,
                              tenant_id=project_id or tenant_id)
        if password is not None:
            return PasswordAuth(auth_url,
                                username=username or self.username,
                                password=password,
                                tenant_id=project_id or tenant_id)

        raise ValueError(
            _("Cannot authenticate without an api_key or password"))
Ejemplo n.º 58
0
    def process_token(self, **kwargs):
        """Extract and process information from the new auth_ref.

        And set the relevant authentication information.
        """
        super(Client, self).process_token(**kwargs)
        if self.auth_ref.domain_scoped:
            if not self.auth_ref.domain_id:
                raise exceptions.AuthorizationFailure(
                    _("Token didn't provide domain_id"))
            self._process_management_url(kwargs.get('region_name'))
            self.domain_name = self.auth_ref.domain_name
            self.domain_id = self.auth_ref.domain_id
        if self._management_url:
            self._management_url = self._management_url.replace('/v2.0', '/v3')
Ejemplo n.º 59
0
def do_tenant_update(kc, args):
    """Update tenant name, description, enabled status."""
    tenant = utils.find_resource(kc.tenants, args.tenant)
    kwargs = {}
    if args.name:
        kwargs.update({'name': args.name})
    if args.description is not None:
        kwargs.update({'description': args.description})
    if args.enabled:
        kwargs.update({'enabled': strutils.bool_from_string(args.enabled)})

    if kwargs == {}:
        print(_("Tenant not updated, no arguments present."))
        return
    tenant.update(**kwargs)
Ejemplo n.º 60
0
def do_endpoint_get(kc, args):
    """Find endpoint filtered by a specific attribute or service type."""
    kwargs = {
        'service_type': args.service,
        'endpoint_type': args.endpoint_type,
    }

    if args.attr and args.value:
        kwargs.update({'attr': args.attr, 'filter_value': args.value})
    elif args.attr or args.value:
        print(_('Both --attr and --value required.'))
        return

    url = kc.service_catalog.url_for(**kwargs)
    utils.print_dict({'%s.%s' % (args.service, args.endpoint_type): url})