~ubuntu-branches/ubuntu/utopic/python-ceilometerclient/utopic

« back to all changes in this revision

Viewing changes to ceilometerclient/openstack/common/apiclient/auth.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, James Page, Chuck Short
  • Date: 2014-01-21 09:53:01 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140121095301-cwxsrtdgddkzprjx
Tags: 1.0.8-0ubuntu1
[ James Page ]
* d/control: Add missing BD on python-babel. 

[ Chuck Short ]
* New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2013 OpenStack Foundation
 
2
# Copyright 2013 Spanish National Research Council.
 
3
# All Rights Reserved.
 
4
#
 
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
 
8
#
 
9
#         http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
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
 
15
#    under the License.
 
16
 
 
17
# E0202: An attribute inherited from %s hide this method
 
18
# pylint: disable=E0202
 
19
 
 
20
import abc
 
21
import argparse
 
22
import logging
 
23
import os
 
24
 
 
25
import six
 
26
from stevedore import extension
 
27
 
 
28
from ceilometerclient.openstack.common.apiclient import exceptions
 
29
 
 
30
 
 
31
logger = logging.getLogger(__name__)
 
32
 
 
33
 
 
34
_discovered_plugins = {}
 
35
 
 
36
 
 
37
def discover_auth_systems():
 
38
    """Discover the available auth-systems.
 
39
 
 
40
    This won't take into account the old style auth-systems.
 
41
    """
 
42
    global _discovered_plugins
 
43
    _discovered_plugins = {}
 
44
 
 
45
    def add_plugin(ext):
 
46
        _discovered_plugins[ext.name] = ext.plugin
 
47
 
 
48
    ep_namespace = "ceilometerclient.openstack.common.apiclient.auth"
 
49
    mgr = extension.ExtensionManager(ep_namespace)
 
50
    mgr.map(add_plugin)
 
51
 
 
52
 
 
53
def load_auth_system_opts(parser):
 
54
    """Load options needed by the available auth-systems into a parser.
 
55
 
 
56
    This function will try to populate the parser with options from the
 
57
    available plugins.
 
58
    """
 
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)
 
66
 
 
67
 
 
68
def load_plugin(auth_system):
 
69
    try:
 
70
        plugin_class = _discovered_plugins[auth_system]
 
71
    except KeyError:
 
72
        raise exceptions.AuthSystemNotFound(auth_system)
 
73
    return plugin_class(auth_system=auth_system)
 
74
 
 
75
 
 
76
def load_plugin_from_args(args):
 
77
    """Load required plugin and populate it with options.
 
78
 
 
79
    Try to guess auth system if it is not specified. Systems are tried in
 
80
    alphabetical order.
 
81
 
 
82
    :type args: argparse.Namespace
 
83
    :raises: AuthorizationFailure
 
84
    """
 
85
    auth_system = args.os_auth_system
 
86
    if auth_system:
 
87
        plugin = load_plugin(auth_system)
 
88
        plugin.parse_opts(args)
 
89
        plugin.sufficient_options()
 
90
        return plugin
 
91
 
 
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)
 
96
        try:
 
97
            plugin.sufficient_options()
 
98
        except exceptions.AuthPluginOptionsMissing:
 
99
            continue
 
100
        return plugin
 
101
    raise exceptions.AuthPluginOptionsMissing(["auth_system"])
 
102
 
 
103
 
 
104
@six.add_metaclass(abc.ABCMeta)
 
105
class BaseAuthPlugin(object):
 
106
    """Base class for authentication plugins.
 
107
 
 
108
    An authentication plugin needs to override at least the authenticate
 
109
    method to be a valid plugin.
 
110
    """
 
111
 
 
112
    auth_system = None
 
113
    opt_names = []
 
114
    common_opt_names = [
 
115
        "auth_system",
 
116
        "username",
 
117
        "password",
 
118
        "tenant_name",
 
119
        "token",
 
120
        "auth_url",
 
121
    ]
 
122
 
 
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)
 
127
 
 
128
    @staticmethod
 
129
    def _parser_add_opt(parser, opt):
 
130
        """Add an option to parser in two variants.
 
131
 
 
132
        :param opt: option name (with underscores)
 
133
        """
 
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
 
138
        parser.add_argument(
 
139
            "--os-%s" % dashed_opt,
 
140
            metavar="<%s>" % dashed_opt,
 
141
            default=arg_default,
 
142
            help=arg_help)
 
143
        parser.add_argument(
 
144
            "--os_%s" % opt,
 
145
            metavar="<%s>" % dashed_opt,
 
146
            help=argparse.SUPPRESS)
 
147
 
 
148
    @classmethod
 
149
    def add_opts(cls, parser):
 
150
        """Populate the parser with the options for this plugin.
 
151
        """
 
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)
 
157
 
 
158
    @classmethod
 
159
    def add_common_opts(cls, parser):
 
160
        """Add options that are common for several plugins.
 
161
        """
 
162
        for opt in cls.common_opt_names:
 
163
            cls._parser_add_opt(parser, opt)
 
164
 
 
165
    @staticmethod
 
166
    def get_opt(opt_name, args):
 
167
        """Return option name and value.
 
168
 
 
169
        :param opt_name: name of the option, e.g., "username"
 
170
        :param args: parsed arguments
 
171
        """
 
172
        return (opt_name, getattr(args, "os_%s" % opt_name, None))
 
173
 
 
174
    def parse_opts(self, args):
 
175
        """Parse the actual auth-system options if any.
 
176
 
 
177
        This method is expected to populate the attribute `self.opts` with a
 
178
        dict containing the options and values needed to make authentication.
 
179
        """
 
180
        self.opts.update(dict(self.get_opt(opt_name, args)
 
181
                              for opt_name in self.opt_names))
 
182
 
 
183
    def authenticate(self, http_client):
 
184
        """Authenticate using plugin defined method.
 
185
 
 
186
        The method usually analyses `self.opts` and performs
 
187
        a request to authentication server.
 
188
 
 
189
        :param http_client: client object that needs authentication
 
190
        :type http_client: HTTPClient
 
191
        :raises: AuthorizationFailure
 
192
        """
 
193
        self.sufficient_options()
 
194
        self._do_authenticate(http_client)
 
195
 
 
196
    @abc.abstractmethod
 
197
    def _do_authenticate(self, http_client):
 
198
        """Protected method for authentication.
 
199
        """
 
200
 
 
201
    def sufficient_options(self):
 
202
        """Check if all required options are present.
 
203
 
 
204
        :raises: AuthPluginOptionsMissing
 
205
        """
 
206
        missing = [opt
 
207
                   for opt in self.opt_names
 
208
                   if not self.opts.get(opt)]
 
209
        if missing:
 
210
            raise exceptions.AuthPluginOptionsMissing(missing)
 
211
 
 
212
    @abc.abstractmethod
 
213
    def token_and_endpoint(self, endpoint_type, service_type):
 
214
        """Return token and endpoint.
 
215
 
 
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,
 
221
                                  admin or adminURL
 
222
        :type endpoint_type: string
 
223
        :returns: tuple of token and endpoint strings
 
224
        :raises: EndpointException
 
225
        """