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
26
from stevedore import extension
28
from ceilometerclient.openstack.common.apiclient import exceptions
31
logger = logging.getLogger(__name__)
34
_discovered_plugins = {}
37
def discover_auth_systems():
38
"""Discover the available auth-systems.
40
This won't take into account the old style auth-systems.
42
global _discovered_plugins
43
_discovered_plugins = {}
46
_discovered_plugins[ext.name] = ext.plugin
48
ep_namespace = "ceilometerclient.openstack.common.apiclient.auth"
49
mgr = extension.ExtensionManager(ep_namespace)
53
def load_auth_system_opts(parser):
54
"""Load options needed by the available auth-systems into a parser.
56
This function will try to populate the parser with options from the
59
group = parser.add_argument_group("Common auth options")
60
BaseAuthPlugin.add_common_opts(group)
61
for name, auth_plugin in _discovered_plugins.iteritems():
62
group = parser.add_argument_group(
63
"Auth-system '%s' options" % name,
64
conflict_handler="resolve")
65
auth_plugin.add_opts(group)
68
def load_plugin(auth_system):
70
plugin_class = _discovered_plugins[auth_system]
72
raise exceptions.AuthSystemNotFound(auth_system)
73
return plugin_class(auth_system=auth_system)
76
def load_plugin_from_args(args):
77
"""Load required plugin and populate it with options.
79
Try to guess auth system if it is not specified. Systems are tried in
82
:type args: argparse.Namespace
83
:raises: AuthorizationFailure
85
auth_system = args.os_auth_system
87
plugin = load_plugin(auth_system)
88
plugin.parse_opts(args)
89
plugin.sufficient_options()
92
for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)):
93
plugin_class = _discovered_plugins[plugin_auth_system]
94
plugin = plugin_class()
95
plugin.parse_opts(args)
97
plugin.sufficient_options()
98
except exceptions.AuthPluginOptionsMissing:
101
raise exceptions.AuthPluginOptionsMissing(["auth_system"])
104
@six.add_metaclass(abc.ABCMeta)
105
class BaseAuthPlugin(object):
106
"""Base class for authentication plugins.
108
An authentication plugin needs to override at least the authenticate
109
method to be a valid plugin.
123
def __init__(self, auth_system=None, **kwargs):
124
self.auth_system = auth_system or self.auth_system
125
self.opts = dict((name, kwargs.get(name))
126
for name in self.opt_names)
129
def _parser_add_opt(parser, opt):
130
"""Add an option to parser in two variants.
132
:param opt: option name (with underscores)
134
dashed_opt = opt.replace("_", "-")
135
env_var = "OS_%s" % opt.upper()
136
arg_default = os.environ.get(env_var, "")
137
arg_help = "Defaults to env[%s]." % env_var
139
"--os-%s" % dashed_opt,
140
metavar="<%s>" % dashed_opt,
145
metavar="<%s>" % dashed_opt,
146
help=argparse.SUPPRESS)
149
def add_opts(cls, parser):
150
"""Populate the parser with the options for this plugin.
152
for opt in cls.opt_names:
153
# use `BaseAuthPlugin.common_opt_names` since it is never
154
# changed in child classes
155
if opt not in BaseAuthPlugin.common_opt_names:
156
cls._parser_add_opt(parser, opt)
159
def add_common_opts(cls, parser):
160
"""Add options that are common for several plugins.
162
for opt in cls.common_opt_names:
163
cls._parser_add_opt(parser, opt)
166
def get_opt(opt_name, args):
167
"""Return option name and value.
169
:param opt_name: name of the option, e.g., "username"
170
:param args: parsed arguments
172
return (opt_name, getattr(args, "os_%s" % opt_name, None))
174
def parse_opts(self, args):
175
"""Parse the actual auth-system options if any.
177
This method is expected to populate the attribute `self.opts` with a
178
dict containing the options and values needed to make authentication.
180
self.opts.update(dict(self.get_opt(opt_name, args)
181
for opt_name in self.opt_names))
183
def authenticate(self, http_client):
184
"""Authenticate using plugin defined method.
186
The method usually analyses `self.opts` and performs
187
a request to authentication server.
189
:param http_client: client object that needs authentication
190
:type http_client: HTTPClient
191
:raises: AuthorizationFailure
193
self.sufficient_options()
194
self._do_authenticate(http_client)
197
def _do_authenticate(self, http_client):
198
"""Protected method for authentication.
201
def sufficient_options(self):
202
"""Check if all required options are present.
204
:raises: AuthPluginOptionsMissing
207
for opt in self.opt_names
208
if not self.opts.get(opt)]
210
raise exceptions.AuthPluginOptionsMissing(missing)
213
def token_and_endpoint(self, endpoint_type, service_type):
214
"""Return token and endpoint.
216
:param service_type: Service type of the endpoint
217
:type service_type: string
218
:param endpoint_type: Type of endpoint.
219
Possible values: public or publicURL,
220
internal or internalURL,
222
:type endpoint_type: string
223
:returns: tuple of token and endpoint strings
224
:raises: EndpointException