1 # Copyright 2013 OpenStack Foundation
2 # Copyright 2013 Spanish National Research Council.
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
17 # E0202: An attribute inherited from %s hide this method
18 # pylint: disable=E0202
20 ########################################################################
22 # THIS MODULE IS DEPRECATED
25 # https://etherpad.openstack.org/p/kilo-escalatorclient-library-proposals for
26 # the discussion leading to this deprecation.
28 # We recommend checking out the python-openstacksdk project
29 # (https://launchpad.net/python-openstacksdk) instead.
31 ########################################################################
38 from stevedore import extension
40 from escalatorclient.openstack.common.apiclient import exceptions
43 _discovered_plugins = {}
46 def discover_auth_systems():
47 """Discover the available auth-systems.
49 This won't take into account the old style auth-systems.
51 global _discovered_plugins
52 _discovered_plugins = {}
55 _discovered_plugins[ext.name] = ext.plugin
57 ep_namespace = "escalatorclient.openstack.common.apiclient.auth"
58 mgr = extension.ExtensionManager(ep_namespace)
62 def load_auth_system_opts(parser):
63 """Load options needed by the available auth-systems into a parser.
65 This function will try to populate the parser with options from the
68 group = parser.add_argument_group("Common auth options")
69 BaseAuthPlugin.add_common_opts(group)
70 for name, auth_plugin in six.iteritems(_discovered_plugins):
71 group = parser.add_argument_group(
72 "Auth-system '%s' options" % name,
73 conflict_handler="resolve")
74 auth_plugin.add_opts(group)
77 def load_plugin(auth_system):
79 plugin_class = _discovered_plugins[auth_system]
81 raise exceptions.AuthSystemNotFound(auth_system)
82 return plugin_class(auth_system=auth_system)
85 def load_plugin_from_args(args):
86 """Load required plugin and populate it with options.
88 Try to guess auth system if it is not specified. Systems are tried in
91 :type args: argparse.Namespace
92 :raises: AuthPluginOptionsMissing
94 auth_system = args.os_auth_system
96 plugin = load_plugin(auth_system)
97 plugin.parse_opts(args)
98 plugin.sufficient_options()
101 for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)):
102 plugin_class = _discovered_plugins[plugin_auth_system]
103 plugin = plugin_class()
104 plugin.parse_opts(args)
106 plugin.sufficient_options()
107 except exceptions.AuthPluginOptionsMissing:
110 raise exceptions.AuthPluginOptionsMissing(["auth_system"])
113 @six.add_metaclass(abc.ABCMeta)
114 class BaseAuthPlugin(object):
115 """Base class for authentication plugins.
117 An authentication plugin needs to override at least the authenticate
118 method to be a valid plugin.
132 def __init__(self, auth_system=None, **kwargs):
133 self.auth_system = auth_system or self.auth_system
134 self.opts = dict((name, kwargs.get(name))
135 for name in self.opt_names)
138 def _parser_add_opt(parser, opt):
139 """Add an option to parser in two variants.
141 :param opt: option name (with underscores)
143 dashed_opt = opt.replace("_", "-")
144 env_var = "OS_%s" % opt.upper()
145 arg_default = os.environ.get(env_var, "")
146 arg_help = "Defaults to env[%s]." % env_var
148 "--os-%s" % dashed_opt,
149 metavar="<%s>" % dashed_opt,
154 metavar="<%s>" % dashed_opt,
155 help=argparse.SUPPRESS)
158 def add_opts(cls, parser):
159 """Populate the parser with the options for this plugin.
161 for opt in cls.opt_names:
162 # use `BaseAuthPlugin.common_opt_names` since it is never
163 # changed in child classes
164 if opt not in BaseAuthPlugin.common_opt_names:
165 cls._parser_add_opt(parser, opt)
168 def add_common_opts(cls, parser):
169 """Add options that are common for several plugins.
171 for opt in cls.common_opt_names:
172 cls._parser_add_opt(parser, opt)
175 def get_opt(opt_name, args):
176 """Return option name and value.
178 :param opt_name: name of the option, e.g., "username"
179 :param args: parsed arguments
181 return (opt_name, getattr(args, "os_%s" % opt_name, None))
183 def parse_opts(self, args):
184 """Parse the actual auth-system options if any.
186 This method is expected to populate the attribute `self.opts` with a
187 dict containing the options and values needed to make authentication.
189 self.opts.update(dict(self.get_opt(opt_name, args)
190 for opt_name in self.opt_names))
192 def authenticate(self, http_client):
193 """Authenticate using plugin defined method.
195 The method usually analyses `self.opts` and performs
196 a request to authentication server.
198 :param http_client: client object that needs authentication
199 :type http_client: HTTPClient
200 :raises: AuthorizationFailure
202 self.sufficient_options()
203 self._do_authenticate(http_client)
206 def _do_authenticate(self, http_client):
207 """Protected method for authentication.
210 def sufficient_options(self):
211 """Check if all required options are present.
213 :raises: AuthPluginOptionsMissing
216 for opt in self.opt_names
217 if not self.opts.get(opt)]
219 raise exceptions.AuthPluginOptionsMissing(missing)
222 def token_and_endpoint(self, endpoint_type, service_type):
223 """Return token and endpoint.
225 :param service_type: Service type of the endpoint
226 :type service_type: string
227 :param endpoint_type: Type of endpoint.
228 Possible values: public or publicURL,
229 internal or internalURL,
231 :type endpoint_type: string
232 :returns: tuple of token and endpoint strings
233 :raises: EndpointException