summaryrefslogtreecommitdiffstats
path: root/keystonemiddleware-moon/keystonemiddleware/auth_token/_auth.py
blob: cf7ed84dc26fd72242bc07d364f64471b15e0737 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import logging

from keystoneclient import auth
from keystoneclient.auth.identity import v2
from keystoneclient.auth import token_endpoint
from keystoneclient import discover
from oslo_config import cfg

from keystonemiddleware.auth_token import _base
from keystonemiddleware.i18n import _, _LW


_LOG = logging.getLogger(__name__)


class AuthTokenPlugin(auth.BaseAuthPlugin):

    def __init__(self, auth_host, auth_port, auth_protocol, auth_admin_prefix,
                 admin_user, admin_password, admin_tenant_name, admin_token,
                 identity_uri, log):

        log.warning(_LW(
            "Use of the auth_admin_prefix, auth_host, auth_port, "
            "auth_protocol, identity_uri, admin_token, admin_user, "
            "admin_password, and admin_tenant_name configuration options is "
            "deprecated in favor of auth_plugin and related options and may "
            "be removed in a future release."))

        # NOTE(jamielennox): it does appear here that our default arguments
        # are backwards. We need to do it this way so that we can handle the
        # same deprecation strategy for CONF and the conf variable.
        if not identity_uri:
            log.warning(_LW('Configuring admin URI using auth fragments. '
                            'This is deprecated, use \'identity_uri\''
                            ' instead.'))

            if ':' in auth_host:
                # Note(dzyu) it is an IPv6 address, so it needs to be wrapped
                # with '[]' to generate a valid IPv6 URL, based on
                # http://www.ietf.org/rfc/rfc2732.txt
                auth_host = '[%s]' % auth_host

            identity_uri = '%s://%s:%s' % (auth_protocol,
                                           auth_host,
                                           auth_port)

            if auth_admin_prefix:
                identity_uri = '%s/%s' % (identity_uri,
                                          auth_admin_prefix.strip('/'))

        self._identity_uri = identity_uri.rstrip('/')

        # FIXME(jamielennox): Yes. This is wrong. We should be determining the
        # plugin to use based on a combination of discovery and inputs. Much
        # of this can be changed when we get keystoneclient 0.10. For now this
        # hardcoded path is EXACTLY the same as the original auth_token did.
        auth_url = '%s/v2.0' % self._identity_uri

        if admin_token:
            log.warning(_LW(
                "The admin_token option in the auth_token middleware is "
                "deprecated and should not be used. The admin_user and "
                "admin_password options should be used instead. The "
                "admin_token option may be removed in a future release."))
            self._plugin = token_endpoint.Token(auth_url, admin_token)
        else:
            self._plugin = v2.Password(auth_url,
                                       username=admin_user,
                                       password=admin_password,
                                       tenant_name=admin_tenant_name)

        self._LOG = log
        self._discover = None

    def get_token(self, *args, **kwargs):
        return self._plugin.get_token(*args, **kwargs)

    def get_endpoint(self, session, interface=None, version=None, **kwargs):
        """Return an endpoint for the client.

        There are no required keyword arguments to ``get_endpoint`` as a plugin
        implementation should use best effort with the information available to
        determine the endpoint.

        :param session: The session object that the auth_plugin belongs to.
        :type session: keystoneclient.session.Session
        :param version: The version number required for this endpoint.
        :type version: tuple or str
        :param str interface: what visibility the endpoint should have.

        :returns: The base URL that will be used to talk to the required
                  service or None if not available.
        :rtype: string
        """
        if interface == auth.AUTH_INTERFACE:
            return self._identity_uri

        if not version:
            # NOTE(jamielennox): This plugin can only be used within auth_token
            # and auth_token will always provide version= with requests.
            return None

        if not self._discover:
            self._discover = discover.Discover(session,
                                               auth_url=self._identity_uri,
                                               authenticated=False)

        if not self._discover.url_for(version):
            # NOTE(jamielennox): The requested version is not supported by the
            # identity server.
            return None

        # NOTE(jamielennox): for backwards compatibility here we don't
        # actually use the URL from discovery we hack it up instead. :(
        # NOTE(blk-u): Normalizing the version is a workaround for bug 1450272.
        # This can be removed once that's fixed. Also fix the docstring for the
        # version parameter to be just "tuple".
        version = discover.normalize_version_number(version)
        if discover.version_match((2, 0), version):
            return '%s/v2.0' % self._identity_uri
        elif discover.version_match((3, 0), version):
            return '%s/v3' % self._identity_uri

        # NOTE(jamielennox): This plugin will only get called from auth_token
        # middleware. The middleware should never request a version that the
        # plugin doesn't know how to handle.
        msg = _('Invalid version asked for in auth_token plugin')
        raise NotImplementedError(msg)

    def invalidate(self):
        return self._plugin.invalidate()

    @classmethod
    def get_options(cls):
        options = super(AuthTokenPlugin, cls).get_options()

        options.extend([
            cfg.StrOpt('auth_admin_prefix',
                       default='',
                       help='Prefix to prepend at the beginning of the path. '
                            'Deprecated, use identity_uri.'),
            cfg.StrOpt('auth_host',
                       default='127.0.0.1',
                       help='Host providing the admin Identity API endpoint. '
                            'Deprecated, use identity_uri.'),
            cfg.IntOpt('auth_port',
                       default=35357,
                       help='Port of the admin Identity API endpoint. '
                            'Deprecated, use identity_uri.'),
            cfg.StrOpt('auth_protocol',
                       default='https',
                       help='Protocol of the admin Identity API endpoint '
                            '(http or https). Deprecated, use identity_uri.'),
            cfg.StrOpt('identity_uri',
                       default=None,
                       help='Complete admin Identity API endpoint. This '
                            'should specify the unversioned root endpoint '
                            'e.g. https://localhost:35357/'),
            cfg.StrOpt('admin_token',
                       secret=True,
                       help='This option is deprecated and may be removed in '
                            'a future release. Single shared secret with the '
                            'Keystone configuration used for bootstrapping a '
                            'Keystone installation, or otherwise bypassing '
                            'the normal authentication process. This option '
                            'should not be used, use `admin_user` and '
                            '`admin_password` instead.'),
            cfg.StrOpt('admin_user',
                       help='Service username.'),
            cfg.StrOpt('admin_password',
                       secret=True,
                       help='Service user password.'),
            cfg.StrOpt('admin_tenant_name',
                       default='admin',
                       help='Service tenant name.'),
        ])

        return options


auth.register_conf_options(cfg.CONF, _base.AUTHTOKEN_GROUP)
AuthTokenPlugin.register_conf_options(cfg.CONF, _base.AUTHTOKEN_GROUP)