1 # Copyright 2016 Cisco Systems, Inc. All rights reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
19 # Module for credentials in Openstack
21 from keystoneauth1.identity import v2
22 from keystoneauth1.identity import v3
23 from keystoneauth1 import session
25 from keystoneclient.exceptions import HTTPClientError
30 class Credentials(object):
32 def get_session(self):
34 if self.clouds_detail:
35 connection = openstack.connect(cloud=self.clouds_detail)
36 cred_session = connection.session
39 'username': self.rc_username,
40 'password': self.rc_password,
41 'auth_url': self.rc_auth_url
44 if self.rc_identity_api_version == 3:
46 'project_name': self.rc_project_name,
47 'project_domain_name': self.rc_project_domain_name,
48 'user_domain_name': self.rc_user_domain_name
50 auth = v3.Password(**dct)
53 'tenant_name': self.rc_tenant_name
55 auth = v2.Password(**dct)
56 cred_session = session.Session(auth=auth, verify=self.rc_cacert)
59 def __parse_openrc(self, file):
60 export_re = re.compile('export OS_([A-Z_]*)="?(.*)')
63 mstr = export_re.match(line)
65 # get rif of posible trailing double quote
66 # the first one was removed by the re
69 if value.endswith('"'):
71 # get rid of password assignment
72 # echo "Please enter your OpenStack Password: "
73 # read -sr OS_PASSWORD_INPUT
74 # export OS_PASSWORD=$OS_PASSWORD_INPUT
75 if value.startswith('$'):
77 # Check if api version is provided
78 # Default is keystone v2
79 if name == 'IDENTITY_API_VERSION':
80 self.rc_identity_api_version = int(value)
82 # now match against wanted variable names
83 elif name == 'USERNAME':
84 self.rc_username = value
85 elif name == 'AUTH_URL':
86 self.rc_auth_url = value
87 elif name == 'TENANT_NAME':
88 self.rc_tenant_name = value
89 elif name == "CACERT":
90 self.rc_cacert = value
91 elif name == "REGION_NAME":
92 self.rc_region_name = value
93 elif name == "PASSWORD":
94 self.rc_password = value
95 elif name == "USER_DOMAIN_NAME":
96 self.rc_user_domain_name = value
97 elif name == "PROJECT_NAME":
98 self.rc_project_name = value
99 elif name == "PROJECT_DOMAIN_NAME":
100 self.rc_project_domain_name = value
102 # /users URL returns exception (HTTP 403) if user is not admin.
103 # try first without the version in case session already has it in
104 # Return HTTP 200 if user is admin
105 def __user_is_admin(self, url):
108 # check if user has admin role in OpenStack project
109 filter = {'service_type': 'identity',
110 'interface': 'public'}
111 self.get_session().get(url, endpoint_filter=filter)
113 except HTTPClientError as exc:
114 if exc.http_status == 403:
116 "User is not admin, no permission to list user roles. Exception: %s", exc)
120 # Read a openrc file and take care of the password
121 # The 2 args are passed from the command line and can be None
123 def __init__(self, openrc_file, clouds_detail, pwd=None, no_env=False):
124 self.rc_password = None
125 self.rc_username = None
126 self.rc_tenant_name = None
127 self.rc_auth_url = None
128 self.rc_cacert = None
129 self.rc_region_name = None
130 self.rc_user_domain_name = None
131 self.rc_project_domain_name = None
132 self.rc_project_name = None
133 self.rc_identity_api_version = 3
134 self.is_admin = False
135 self.clouds_detail = clouds_detail
139 if isinstance(openrc_file, str):
140 if os.path.exists(openrc_file):
141 with open(openrc_file) as rc_file:
142 self.__parse_openrc(rc_file)
144 LOG.error('Error: rc file does not exist %s', openrc_file)
147 self.__parse_openrc(openrc_file)
148 elif not clouds_detail and not no_env:
149 # no openrc file passed - we assume the variables have been
150 # sourced by the calling shell
151 # just check that they are present
152 if 'OS_IDENTITY_API_VERSION' in os.environ:
153 self.rc_identity_api_version = int(os.environ['OS_IDENTITY_API_VERSION'])
155 if self.rc_identity_api_version == 2:
156 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
157 if varname not in os.environ:
158 LOG.warning('%s is missing', varname)
161 self.rc_username = os.environ['OS_USERNAME']
162 self.rc_auth_url = os.environ['OS_AUTH_URL']
163 self.rc_tenant_name = os.environ['OS_TENANT_NAME']
164 if 'OS_REGION_NAME' in os.environ:
165 self.rc_region_name = os.environ['OS_REGION_NAME']
166 elif self.rc_identity_api_version == 3:
167 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_PROJECT_NAME',
168 'OS_PROJECT_DOMAIN_NAME', 'OS_USER_DOMAIN_NAME']:
169 if varname not in os.environ:
170 LOG.warning('%s is missing', varname)
173 self.rc_username = os.environ['OS_USERNAME']
174 self.rc_auth_url = os.environ['OS_AUTH_URL']
175 self.rc_project_name = os.environ['OS_PROJECT_NAME']
176 self.rc_project_domain_name = os.environ['OS_PROJECT_DOMAIN_NAME']
177 self.rc_user_domain_name = os.environ['OS_USER_DOMAIN_NAME']
178 if 'OS_CACERT' in os.environ:
179 self.rc_cacert = os.environ['OS_CACERT']
182 # always override with CLI argument if provided
183 if not clouds_detail:
185 self.rc_password = pwd
186 # if password not know, check from env variable
187 elif self.rc_auth_url and not self.rc_password and success:
188 if 'OS_PASSWORD' in os.environ and not no_env:
189 self.rc_password = os.environ['OS_PASSWORD']
191 # interactively ask for password
192 self.rc_password = getpass.getpass(
193 'Please enter your OpenStack Password: ')
194 if not self.rc_password:
195 self.rc_password = ""
199 # /users URL returns exception (HTTP 403) if user is not admin.
200 # try first without the version in case session already has it in
201 # Return HTTP 200 if user is admin
202 self.is_admin = self.__user_is_admin('/users') or self.__user_is_admin(
203 '/v2/users') or self.__user_is_admin('/v3/users')
204 except Exception as e:
205 LOG.warning("Error occurred during Openstack API access. "
206 "Unable to check user is admin. Exception: %s", e)