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 self.__parse_openrc(open(openrc_file))
143 LOG.error('Error: rc file does not exist %s', openrc_file)
146 self.__parse_openrc(openrc_file)
147 elif not clouds_detail and not no_env:
148 # no openrc file passed - we assume the variables have been
149 # sourced by the calling shell
150 # just check that they are present
151 if 'OS_IDENTITY_API_VERSION' in os.environ:
152 self.rc_identity_api_version = int(os.environ['OS_IDENTITY_API_VERSION'])
154 if self.rc_identity_api_version == 2:
155 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
156 if varname not in os.environ:
157 LOG.warning('%s is missing', varname)
160 self.rc_username = os.environ['OS_USERNAME']
161 self.rc_auth_url = os.environ['OS_AUTH_URL']
162 self.rc_tenant_name = os.environ['OS_TENANT_NAME']
163 if 'OS_REGION_NAME' in os.environ:
164 self.rc_region_name = os.environ['OS_REGION_NAME']
165 elif self.rc_identity_api_version == 3:
166 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_PROJECT_NAME',
167 'OS_PROJECT_DOMAIN_NAME', 'OS_USER_DOMAIN_NAME']:
168 if varname not in os.environ:
169 LOG.warning('%s is missing', varname)
172 self.rc_username = os.environ['OS_USERNAME']
173 self.rc_auth_url = os.environ['OS_AUTH_URL']
174 self.rc_project_name = os.environ['OS_PROJECT_NAME']
175 self.rc_project_domain_name = os.environ['OS_PROJECT_DOMAIN_NAME']
176 self.rc_user_domain_name = os.environ['OS_USER_DOMAIN_NAME']
177 if 'OS_CACERT' in os.environ:
178 self.rc_cacert = os.environ['OS_CACERT']
181 # always override with CLI argument if provided
182 if not clouds_detail:
184 self.rc_password = pwd
185 # if password not know, check from env variable
186 elif self.rc_auth_url and not self.rc_password and success:
187 if 'OS_PASSWORD' in os.environ and not no_env:
188 self.rc_password = os.environ['OS_PASSWORD']
190 # interactively ask for password
191 self.rc_password = getpass.getpass(
192 'Please enter your OpenStack Password: ')
193 if not self.rc_password:
194 self.rc_password = ""
198 # /users URL returns exception (HTTP 403) if user is not admin.
199 # try first without the version in case session already has it in
200 # Return HTTP 200 if user is admin
201 self.is_admin = self.__user_is_admin('/users') or self.__user_is_admin(
202 '/v2/users') or self.__user_is_admin('/v3/users')
203 except Exception as e:
204 LOG.warning("Error occurred during Openstack API access. "
205 "Unable to check user is admin. Exception: %s", e)