blob: 37967e1d4628ff629a96642094a3520d950aa561 [file] [log] [blame]
demx8as6a93cb372021-06-06 16:05:58 +02001#!/usr/bin/env python
demskeq8ef656992024-03-20 08:50:14 +01002################################################################################
3# Copyright 2021 highstreet technologies GmbH
demx8as6a93cb372021-06-06 16:05:58 +02004#
5# Licensed under the Apache License, Version 2.0 (the 'License');
6# you may not use this file except in compliance with the License.
7# You may obtain 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,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18# importing the sys, json, requests library
demskeq8ef656992024-03-20 08:50:14 +010019from sqlite3 import TimeFromTicks
20from jproperties import Properties
demx8as6a93cb372021-06-06 16:05:58 +020021import os
22import sys
23import json
demx8as6f81ad302022-09-15 14:19:17 +020024import time
demx8as6b5ec0302023-07-06 14:09:11 +000025import re
demskeq8ef656992024-03-20 08:50:14 +010026import requests
27import getpass
demx8as6f81ad302022-09-15 14:19:17 +020028import warnings
demx8as6f81ad302022-09-15 14:19:17 +020029from typing import List
demskeq8ef656992024-03-20 08:50:14 +010030
demx8as6f81ad302022-09-15 14:19:17 +020031warnings.filterwarnings('ignore', message='Unverified HTTPS request')
demskeq8ef656992024-03-20 08:50:14 +010032
33
demx8as6a93cb372021-06-06 16:05:58 +020034# global configurations
demskeq8ef656992024-03-20 08:50:14 +010035def get_env(name):
demx8as6f81ad302022-09-15 14:19:17 +020036 configs = Properties()
demskeq8ef656992024-03-20 08:50:14 +010037 envFile = os.path.dirname(os.path.abspath(__file__)) + '/' + '../' + '.env'
38
39 with open(envFile, "rb") as read_prop:
demx8as6f81ad302022-09-15 14:19:17 +020040 configs.load(read_prop)
demx8as6b5ec0302023-07-06 14:09:11 +000041 value = configs.get(name).data
42
43 regex = r"\$\{([^\}]+)\}"
44 matches = re.finditer(regex, value)
45 while True:
46 match = next(matches, None)
47 if match is None:
48 break
demskeq8ef656992024-03-20 08:50:14 +010049 inner = get_env(match.group(1))
50 value = value.replace("${" + match.group(1) + "}", inner)
demx8as6b5ec0302023-07-06 14:09:11 +000051 return value
demx8as6f81ad302022-09-15 14:19:17 +020052
53
demskeq8ef656992024-03-20 08:50:14 +010054def loadArgs(args: List[str]) -> tuple:
55 realmFile = os.path.dirname(os.path.abspath(__file__)) + '/o-ran-sc-realm.json'
56 authFile = os.path.dirname(os.path.abspath(__file__)) + '/authentication.json'
57 readyTimeout = 180
demx8as6f81ad302022-09-15 14:19:17 +020058 args.pop(0)
59 while len(args) > 0:
60 arg = args.pop(0)
61 if arg == '--auth' and len(args) > 0:
demskeq8ef656992024-03-20 08:50:14 +010062 authFile = args.pop(0)
63 print('overwriting auth file: {}'.format(authFile))
demx8as6f81ad302022-09-15 14:19:17 +020064 elif arg == '--realm' and len(args) > 0:
demskeq8ef656992024-03-20 08:50:14 +010065 realmFile = args.pop(0)
66 print('overwriting realm file: {}'.format(realmFile))
demx8as6f81ad302022-09-15 14:19:17 +020067 elif arg == '--timeout' and len(args) > 0:
demskeq8ef656992024-03-20 08:50:14 +010068 readyTimeout = int(args.pop(0))
69 print('waiting for ready {} seconds'.format(readyTimeout))
demx8as6f81ad302022-09-15 14:19:17 +020070
demskeq8ef656992024-03-20 08:50:14 +010071 return (realmFile, authFile, readyTimeout)
demx8as6f81ad302022-09-15 14:19:17 +020072
73
74def isReady(timeoutSeconds=180):
demx8as6cd178822023-07-01 13:44:31 +000075 url = getBaseUrl()
demskeq8ef656992024-03-20 08:50:14 +010076 print(url)
77 response = None
78 print("waiting for ready state", end='')
demx8as6f81ad302022-09-15 14:19:17 +020079 while timeoutSeconds > 0:
80 try:
81 response = requests.get(url, verify=False, headers={})
demskeq8ef656992024-03-20 08:50:14 +010082 print(response)
demx8as6f81ad302022-09-15 14:19:17 +020083 except:
demskeq8ef656992024-03-20 08:50:14 +010084 pass
demx8as6f81ad302022-09-15 14:19:17 +020085 if response is not None and response.status_code == 200:
demskeq8ef656992024-03-20 08:50:14 +010086 print('succeeded')
demx8as6f81ad302022-09-15 14:19:17 +020087 return True
88 time.sleep(1)
89 timeoutSeconds -= 1
demskeq8ef656992024-03-20 08:50:14 +010090 print('.', end='', flush=True)
demx8as6f81ad302022-09-15 14:19:17 +020091 return False
92
93
94def getBaseUrl():
demskeq8ef656992024-03-20 08:50:14 +010095 try:
96 if get_env("USE_LOCAL_HOST_FOR_IDENTITY_CONFIG").strip("'\"") == "true":
97 return get_env("IDENTITY_PROVIDER_URL_LOCAL_HOST")
98 except AttributeError:
99 print("Using IDENTITY_PROVIDER_URL")
100 return get_env("IDENTITY_PROVIDER_URL")
demx8as6cd178822023-07-01 13:44:31 +0000101
102
demskeq8ef656992024-03-20 08:50:14 +0100103# Request a token for futher communication
demx8as6a93cb372021-06-06 16:05:58 +0200104def getToken():
demx8as6f81ad302022-09-15 14:19:17 +0200105 url = base + '/realms/master/protocol/openid-connect/token'
demx8as6a93cb372021-06-06 16:05:58 +0200106 headers = {
107 'content-type': 'application/x-www-form-urlencoded',
108 'accept': 'application/json'
109 }
110 body = {
demx8as6f81ad302022-09-15 14:19:17 +0200111 'client_id': 'admin-cli',
112 'grant_type': 'password',
113 'username': username,
114 'password': password
demx8as6a93cb372021-06-06 16:05:58 +0200115 }
116 try:
demskeq8ef656992024-03-20 08:50:14 +0100117 response = requests.post(url, verify=False, auth=(username, password), data=body, headers=headers)
demx8as6a93cb372021-06-06 16:05:58 +0200118 except requests.exceptions.Timeout:
demx8as6f81ad302022-09-15 14:19:17 +0200119 sys.exit('HTTP request failed, please check you internet connection.')
demx8as6a93cb372021-06-06 16:05:58 +0200120 except requests.exceptions.TooManyRedirects:
demx8as6f81ad302022-09-15 14:19:17 +0200121 sys.exit('HTTP request failed, please check your proxy settings.')
demx8as6a93cb372021-06-06 16:05:58 +0200122 except requests.exceptions.RequestException as e:
demx8as6f81ad302022-09-15 14:19:17 +0200123 # catastrophic error. bail.
124 raise SystemExit(e)
demx8as6a93cb372021-06-06 16:05:58 +0200125
126 if response.status_code >= 200 and response.status_code < 300:
demx8as6f81ad302022-09-15 14:19:17 +0200127 print('Got token!')
128 return response.json()['access_token']
demx8as6a93cb372021-06-06 16:05:58 +0200129 else:
demx8as6f81ad302022-09-15 14:19:17 +0200130 sys.exit('Getting token failed.')
demx8as6a93cb372021-06-06 16:05:58 +0200131
demskeq8ef656992024-03-20 08:50:14 +0100132
demx8as6a93cb372021-06-06 16:05:58 +0200133# create the default realm from file
demx8as6f81ad302022-09-15 14:19:17 +0200134def createRealm(token, realm):
135 url = base + '/admin/realms'
136 auth = 'bearer ' + token
137 headers = {
138 'content-type': 'application/json',
139 'accept': 'application/json',
140 'authorization': auth
141 }
142 try:
demskeq8ef656992024-03-20 08:50:14 +0100143 response = requests.post(url, verify=False, json=realm, headers=headers)
demx8as6f81ad302022-09-15 14:19:17 +0200144 except requests.exceptions.Timeout:
145 sys.exit('HTTP request failed, please check you internet connection.')
146 except requests.exceptions.TooManyRedirects:
147 sys.exit('HTTP request failed, please check your proxy settings.')
148 except requests.exceptions.RequestException as e:
149 # catastrophic error. bail.
150 raise SystemExit(e)
151
152 return response.status_code >= 200 and response.status_code < 300
demx8as6a93cb372021-06-06 16:05:58 +0200153
demskeq8ef656992024-03-20 08:50:14 +0100154
demx8as6a93cb372021-06-06 16:05:58 +0200155# Check if default realm exists
demx8as6f81ad302022-09-15 14:19:17 +0200156def checkRealmExists(token, realmId):
157 url = base + '/admin/realms/' + realmId
158 auth = 'bearer ' + token
159 headers = {
160 'accept': 'application/json',
161 'authorization': auth
162 }
163 try:
164 response = requests.get(url, verify=False, headers=headers)
165 except requests.exceptions.Timeout:
166 sys.exit('HTTP request failed, please check you internet connection.')
167 except requests.exceptions.TooManyRedirects:
168 sys.exit('HTTP request failed, please check your proxy settings.')
169 except requests.exceptions.RequestException as e:
170 # catastrophic error. bail.
171 raise SystemExit(e)
172
173 if response.status_code >= 200 and response.status_code < 300:
174 return realmId == response.json()['id']
175 else:
176 # sys.exit('Getting realm failed.')
177 return False
demx8as6a93cb372021-06-06 16:05:58 +0200178
demskeq8ef656992024-03-20 08:50:14 +0100179
demx8as6a93cb372021-06-06 16:05:58 +0200180# create a user in default realm
demx8as6f81ad302022-09-15 14:19:17 +0200181def createUser(token, realmConfig, user):
182 realmId = realmConfig['id']
183 url = base + '/admin/realms/' + realmId + '/users'
184 auth = 'bearer ' + token
185 headers = {
186 'accept': 'application/json',
187 'authorization': auth
188 }
189 try:
190 response = requests.post(url, verify=False, json=user, headers=headers)
191 except requests.exceptions.Timeout:
192 sys.exit('HTTP request failed, please check you internet connection.')
193 except requests.exceptions.TooManyRedirects:
194 sys.exit('HTTP request failed, please check your proxy settings.')
195 except requests.exceptions.RequestException as e:
196 # catastrophic error. bail.
197 raise SystemExit(e)
198
199 if response.status_code >= 200 and response.status_code < 300:
200 print('User', user['username'], 'created!')
201 else:
202 print('User creation', user['username'], 'failed!\n', response.text)
demx8as6a93cb372021-06-06 16:05:58 +0200203
demskeq8ef656992024-03-20 08:50:14 +0100204
demx8as6a93cb372021-06-06 16:05:58 +0200205# creates User accounts in realm based a file
demx8as6f81ad302022-09-15 14:19:17 +0200206def createUsers(token, realmConfig, authConfig):
207 for user in authConfig['users']:
208 createUser(token, realmConfig, user)
209
210 # create a user based on system user
211 systemUser = {
212 "firstName": getpass.getuser(),
213 "lastName": "",
214 "email": getpass.getuser() + "@sdnr.onap.org",
215 "enabled": "true",
216 "username": getpass.getuser(),
217 "credentials": [
218 {
219 "type": "password",
220 "value": password,
demskeq8ef656992024-03-20 08:50:14 +0100221 "temporary": False
demx8as6f81ad302022-09-15 14:19:17 +0200222 }
demx8as6cd178822023-07-01 13:44:31 +0000223 ]
demx8as6f81ad302022-09-15 14:19:17 +0200224 }
225 createUser(token, realmConfig, systemUser)
demx8as6a93cb372021-06-06 16:05:58 +0200226
demskeq8ef656992024-03-20 08:50:14 +0100227
demx8as6a93cb372021-06-06 16:05:58 +0200228# Grants a role to a user
demskeq8ef656992024-03-20 08:50:14 +0100229def addUserRole(user: dict, role: list, options: dict):
demx8as6f81ad302022-09-15 14:19:17 +0200230 url = options['url'] + '/' + user['id'] + '/role-mappings/realm'
231 try:
demskeq8ef656992024-03-20 08:50:14 +0100232 for irole in role:
233 response = requests.post(url, verify=False, json=[{'id': irole['id'], 'name': irole['name']}],
234 headers=options['headers'])
235 if response.status_code >= 200 and response.status_code < 300:
236 print('User role', user['username'], irole['name'], 'created!')
237 else:
238 print('Creation of user role', user['username'], irole['name'], 'failed!\n', response.text)
demx8as6f81ad302022-09-15 14:19:17 +0200239 except requests.exceptions.Timeout:
240 sys.exit('HTTP request failed, please check you internet connection.')
241 except requests.exceptions.TooManyRedirects:
242 sys.exit('HTTP request failed, please check your proxy settings.')
243 except requests.exceptions.RequestException as e:
244 # catastrophic error. bail.
245 raise SystemExit(e)
246
demx8as6a93cb372021-06-06 16:05:58 +0200247
248# searches for the role of a given user
demx8as6f81ad302022-09-15 14:19:17 +0200249def findRole(username: str, authConfig: dict, realmConfig: dict) -> dict:
demskeq8ef656992024-03-20 08:50:14 +0100250 roleList = []
251 roleNames = []
demx8as6f81ad302022-09-15 14:19:17 +0200252 roleName = 'administration'
253 for grant in authConfig['grants']:
254 if grant['username'] == username:
255 roleName = grant['role']
demskeq8ef656992024-03-20 08:50:14 +0100256 roleNames = roleName.split(",") # A user can have multiple roles, comma separated
257 for iroleName in roleNames:
258 for role in realmConfig['roles']['realm']:
259 if role['name'] == iroleName:
260 roleList.append(role)
261 return roleList
262
demx8as6a93cb372021-06-06 16:05:58 +0200263
264# adds roles to users
demx8as6f81ad302022-09-15 14:19:17 +0200265def addUserRoles(token, realmConfig, authConfig):
266 realmId = realmConfig['id']
267 url = base + '/admin/realms/' + realmId + '/users'
268 auth = 'bearer ' + token
269 headers = {
270 'content-type': 'application/json',
271 'accept': 'application/json',
272 'authorization': auth
demx8as6a93cb372021-06-06 16:05:58 +0200273 }
demx8as6f81ad302022-09-15 14:19:17 +0200274 try:
275 response = requests.get(url, verify=False, headers=headers)
276 except requests.exceptions.Timeout:
277 sys.exit('HTTP request failed, please check you internet connection.')
278 except requests.exceptions.TooManyRedirects:
279 sys.exit('HTTP request failed, please check your proxy settings.')
280 except requests.exceptions.RequestException as e:
281 # catastrophic error. bail.
282 raise SystemExit(e)
283
284 if response.status_code >= 200 and response.status_code < 300:
285 users = response.json()
286 options = {
287 "url": url,
288 "auth": auth,
289 "headers": headers
290 }
291 for user in users:
292 role = findRole(user['username'], authConfig, realmConfig)
293 addUserRole(user, role, options)
294 else:
295 sys.exit('Getting users failed.')
demx8as6a93cb372021-06-06 16:05:58 +0200296
demskeq8ef656992024-03-20 08:50:14 +0100297
demx8as6a93cb372021-06-06 16:05:58 +0200298# main
demx8as6f81ad302022-09-15 14:19:17 +0200299
demskeq8ef656992024-03-20 08:50:14 +0100300(realmFile, authFile, readyTimeout) = loadArgs(sys.argv)
301username = get_env('ADMIN_USERNAME')
302password = get_env('ADMIN_PASSWORD')
demx8as6f81ad302022-09-15 14:19:17 +0200303base = getBaseUrl()
304isReady(readyTimeout)
demx8as6a93cb372021-06-06 16:05:58 +0200305token = getToken()
306if token:
demx8as6f81ad302022-09-15 14:19:17 +0200307 with open(realmFile) as file:
308 realmConfig = json.load(file)
309 if not checkRealmExists(token, realmConfig['id']):
310 createRealm(token, realmConfig)
demx8as6a93cb372021-06-06 16:05:58 +0200311
demx8as6f81ad302022-09-15 14:19:17 +0200312 with open(authFile) as authConfig:
313 authConfig = json.load(authConfig)
314 createUsers(token, realmConfig, authConfig)
315 addUserRoles(token, realmConfig, authConfig)
316 exit(0)
317exit(1)