mirror of
https://git.isptech.ru/ISPsystem/isp-maintenance.git
synced 2025-02-01 02:50:51 +01:00
Add: auth cmd prototype, dummy_platform for api
This commit is contained in:
parent
bb3b20e6c8
commit
72bfeb9193
@ -1,59 +0,0 @@
|
||||
# ? docker-compose.yml for development environment
|
||||
|
||||
# ! To start development you need to create a directory ./dummy_platform.
|
||||
# ? Place files from the test platform into it:
|
||||
# ? VM6:
|
||||
# ? /opt/ispsystem/vm/config.json - configuration file
|
||||
# ? /opt/ispsystem/vm/mysql - database directory
|
||||
# ? DCI6:
|
||||
# ? /opt/ispsystem/dci/config.json - configuration file
|
||||
# ? /opt/ispsystem/dci/mysql - database directory
|
||||
|
||||
# ? Create ./.env file and fill it with required vars:
|
||||
# ? PLATFORM_TYPE='vm'
|
||||
# ? Database container:
|
||||
# ? MYSQL_DATABASE="database name"
|
||||
# ? MYSQL_ROOT_PASSWORD="super secret password from config.json"
|
||||
|
||||
# ? Launch:
|
||||
# ? docker-compose up -d --force-recreate
|
||||
# ? docker attach mgrctl
|
||||
|
||||
services:
|
||||
mgrctl:
|
||||
container_name: mgrctl
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- APP_VERSION=${APP_VERSION}
|
||||
- APP_DIR=${APP_DIR}
|
||||
- SRC_DIR=${SRC_DIR}
|
||||
- PKG_NAME=${PKG_NAME}
|
||||
- PKG_VERSION=${PKG_VERSION}
|
||||
networks:
|
||||
vm_box_net: null
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./dummy_platform/opt/ispsystem/${PLATFORM_TYPE}/config.json
|
||||
target: /opt/ispsystem/${PLATFORM_TYPE}/config.json
|
||||
env_file:
|
||||
- ./.env
|
||||
tty: true
|
||||
stdin_open: true
|
||||
mysql:
|
||||
container_name: mysql
|
||||
image: docker-registry.ispsystem.com/mysql:5
|
||||
volumes:
|
||||
- ./dummy_platform/opt/ispsystem/${PLATFORM_TYPE}/mysql:/var/lib/mysql
|
||||
env_file:
|
||||
- ./.env
|
||||
labels:
|
||||
autoconf_mysql: "true"
|
||||
networks:
|
||||
vm_box_net: null
|
||||
command: --group-concat-max-len=131072 --max-connections=1000 --optimizer-search-depth=0
|
||||
|
||||
networks:
|
||||
vm_box_net:
|
||||
driver: bridge
|
@ -3,18 +3,52 @@ import json
|
||||
import urllib
|
||||
import requests
|
||||
|
||||
from mgrctl.settings.api import INPUT_HOSTNAME, INPUT_PORT, HEADERS
|
||||
from mgrctl.settings.api import INPUT_URL, HEADERS
|
||||
from mgrctl.settings.platform import (
|
||||
PLATFORM_TYPE,
|
||||
PLATFORM_VERIFY_SSL,
|
||||
PLATFORM_DUMMY,
|
||||
PLATFORM_DUMMY_VM6_API_URL,
|
||||
PLATFORM_DUMMY_VM6_EMAIL,
|
||||
PLATFORM_DUMMY_VM6_PASSWORD,
|
||||
PLATFORM_DUMMY_VM6_TOKEN,
|
||||
PLATFORM_DUMMY_DCI6_API_URL,
|
||||
PLATFORM_DUMMY_DCI6_EMAIL,
|
||||
PLATFORM_DUMMY_DCI6_PASSWORD,
|
||||
PLATFORM_DUMMY_DCI6_TOKEN
|
||||
)
|
||||
|
||||
|
||||
class BaseAPI(object):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
def __init__(self):
|
||||
"""Announces required parameters"""
|
||||
internal_api_url = f'http://{INPUT_HOSTNAME}:{INPUT_PORT}'
|
||||
self.API_URL = api_url if api_url else internal_api_url
|
||||
if PLATFORM_TYPE == 'vm':
|
||||
if PLATFORM_DUMMY:
|
||||
self.API_URL = PLATFORM_DUMMY_VM6_API_URL
|
||||
self.AUTH_TYPE = 'Public'
|
||||
self.HEADERS = {'x-xsrf-token': PLATFORM_DUMMY_VM6_TOKEN}
|
||||
self.EMAIL = PLATFORM_DUMMY_VM6_EMAIL
|
||||
self.PASSWORD = PLATFORM_DUMMY_VM6_PASSWORD
|
||||
else:
|
||||
self.API_URL = INPUT_URL
|
||||
self.AUTH_TYPE = 'Internal'
|
||||
self.HEADERS = HEADERS
|
||||
|
||||
if PLATFORM_TYPE == 'dci':
|
||||
if PLATFORM_DUMMY:
|
||||
self.API_URL = PLATFORM_DUMMY_DCI6_API_URL
|
||||
self.AUTH_TYPE = 'Public'
|
||||
self.HEADERS = {'x-xsrf-token': PLATFORM_DUMMY_DCI6_TOKEN}
|
||||
self.EMAIL = PLATFORM_DUMMY_DCI6_EMAIL
|
||||
self.PASSWORD = PLATFORM_DUMMY_DCI6_PASSWORD
|
||||
else:
|
||||
self.API_URL = INPUT_URL
|
||||
self.AUTH_TYPE = 'Internal'
|
||||
self.HEADERS = HEADERS
|
||||
|
||||
self.API_VERSION = 'v3'
|
||||
self.API_DEFINITION = 'api'
|
||||
self.HEADERS = HEADERS
|
||||
self.VERIFY_SSL = verify_ssl
|
||||
self.VERIFY_SSL = PLATFORM_VERIFY_SSL
|
||||
|
||||
def _gen_request_url(self, url):
|
||||
return f'{self.API_URL}/{self.API_DEFINITION}/{self.API_VERSION}{url}'
|
||||
@ -61,69 +95,26 @@ class BaseAPI(object):
|
||||
print(response)
|
||||
raise sys.exit()
|
||||
|
||||
def get(self, url, headers={}, data={}):
|
||||
return self.call_api(url, headers, data, method='GET')
|
||||
|
||||
def post(self, url, headers={}, data={}):
|
||||
return self.call_api(url, headers, data, method='POST')
|
||||
|
||||
|
||||
class BaseAuthAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
"""
|
||||
Init class for /auth/v4 requests
|
||||
|
||||
Args:
|
||||
api_url (str, optional): url api host. Defaults to None.
|
||||
If None will use from settings.api.INPUT_HOSTNAME:INPUT_PORT
|
||||
|
||||
verify_ssl (bool, optional): Isn't recommended. Defaults to True.
|
||||
Use only for testing if you don't have root sign SSL cert.
|
||||
"""
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_VERSION = 'v4'
|
||||
self.API_DEFINITION = 'auth'
|
||||
|
||||
def get_auth_token(self, email: str, password: str) -> dict:
|
||||
"""
|
||||
Get auth token for authentication
|
||||
|
||||
Arg:
|
||||
email (str): user email
|
||||
password (str): user password
|
||||
|
||||
Returns:
|
||||
response (dict): {
|
||||
"confirmed": true,
|
||||
"expires_at": "date time",
|
||||
"id": "int",
|
||||
"token": "str"
|
||||
}
|
||||
"""
|
||||
def get_auth_token(self, email=None, password=None) -> dict:
|
||||
email = self.EMAIL if not email else email
|
||||
password = self.PASSWORD if not password else password
|
||||
return self.call_api(
|
||||
url='/public/token',
|
||||
method='POST',
|
||||
data={'email': email, 'password': password}
|
||||
)
|
||||
|
||||
def get_auth_key(self, token: str, user, auth_type='Internal') -> dict:
|
||||
"""
|
||||
Key authentication
|
||||
|
||||
Args:
|
||||
token (str): auth token
|
||||
user (str or int): user id or email
|
||||
auth_type (str, optional): May be Public for public auth.
|
||||
Defaults to 'Internal'.
|
||||
|
||||
Returns:
|
||||
response (dict): {
|
||||
"id": "int",
|
||||
"key": "str"
|
||||
}
|
||||
"""
|
||||
def get_auth_key(self, token=None, user=None) -> dict:
|
||||
headers = {}
|
||||
if auth_type == 'Public':
|
||||
user = self.EMAIL if not user else user
|
||||
if token:
|
||||
headers = self.make_auth_header(token)
|
||||
return self.call_api(
|
||||
url=f'/user/{user}/key',
|
||||
@ -132,32 +123,22 @@ class BaseAuthAPI(BaseAPI):
|
||||
)
|
||||
|
||||
def make_auth_header(self, token: str) -> dict:
|
||||
"""
|
||||
Generate dict for auth header
|
||||
|
||||
Args:
|
||||
token (str): auth token
|
||||
|
||||
Returns:
|
||||
dict: {'x-xsrf-token': token} use it for request headers
|
||||
"""
|
||||
return {'x-xsrf-token': token}
|
||||
|
||||
def whoami(self, token: str) -> dict:
|
||||
def whoami(self) -> dict:
|
||||
return self.call_api(
|
||||
url='/whoami',
|
||||
method='GET',
|
||||
headers=self.make_auth_header(token)
|
||||
method='GET'
|
||||
)
|
||||
|
||||
|
||||
class BaseIpAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'ip'
|
||||
|
||||
|
||||
class BaseDnsProxyAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'dnsproxy'
|
||||
|
@ -6,8 +6,8 @@ class AuthAPI(BaseAuthAPI):
|
||||
|
||||
|
||||
class BackupAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_VERSION = 'v4'
|
||||
self.API_DEFINITION = 'backup'
|
||||
|
||||
@ -17,20 +17,20 @@ class DnsProxyAPI(BaseDnsProxyAPI):
|
||||
|
||||
|
||||
class EserviceAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'eservice'
|
||||
|
||||
|
||||
class IsoAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'iso'
|
||||
|
||||
|
||||
class IpmiAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'ipmiproxy'
|
||||
|
||||
|
||||
@ -39,13 +39,13 @@ class IpAPI(BaseIpAPI):
|
||||
|
||||
|
||||
class ReportAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_VERSION = 'v4'
|
||||
self.API_DEFINITION = 'report'
|
||||
|
||||
|
||||
class UpdaterAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'updater'
|
||||
|
@ -14,6 +14,6 @@ class IpAPI(BaseIpAPI):
|
||||
|
||||
|
||||
class VmAPI(BaseAPI):
|
||||
def __init__(self, api_url=None, verify_ssl=True):
|
||||
super().__init__(api_url, verify_ssl)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.API_DEFINITION = 'vm'
|
||||
|
@ -1,9 +1,11 @@
|
||||
import click
|
||||
|
||||
from mgrctl.db.vm6.databases import isp_database
|
||||
from mgrctl.db.vm6.models import AuthUser
|
||||
|
||||
from mgrctl.apps.vm6.auth import __version__
|
||||
from mgrctl.api.vm6 import AuthAPI
|
||||
from mgrctl.utils.api_users import UserAPI
|
||||
|
||||
|
||||
user_cursor = UserAPI(callback_class=AuthAPI)
|
||||
|
||||
|
||||
@click.group(help='auth cmd for auth in VMmanager 6')
|
||||
@ -16,16 +18,79 @@ def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command(help='show all users and their roles on platform (DEMO EXAMPLE)')
|
||||
def users():
|
||||
# check and init connection to db:
|
||||
isp_database.connect()
|
||||
# get all fields from auth_user table
|
||||
# SELECT * FROM auth_user;
|
||||
all_users = AuthUser.select()
|
||||
# Iterate fields and print to console users' email and role
|
||||
for user in all_users:
|
||||
result = f'{user.email} | {user.roles[0]}'
|
||||
click.echo(result)
|
||||
# Close connection
|
||||
isp_database.close()
|
||||
@cli.group(help='Manage users')
|
||||
def user():
|
||||
pass
|
||||
|
||||
|
||||
@user.command(help='List users')
|
||||
@click.option(
|
||||
'--all',
|
||||
is_flag=True,
|
||||
required=False,
|
||||
help='Show all users'
|
||||
)
|
||||
@click.option(
|
||||
'--admins',
|
||||
is_flag=True,
|
||||
required=False,
|
||||
help='Show all active admins',
|
||||
)
|
||||
def ls(all, admins):
|
||||
if all:
|
||||
user_cursor.echo_users(role='all')
|
||||
elif admins:
|
||||
user_cursor.echo_users(role='admin')
|
||||
else:
|
||||
user_cursor.echo_users(role='all')
|
||||
|
||||
|
||||
@user.command(help='Generate access key and return auth link(s)')
|
||||
@click.option(
|
||||
'--id',
|
||||
required=False,
|
||||
type=int,
|
||||
help='User id'
|
||||
)
|
||||
@click.option(
|
||||
'--count',
|
||||
required=False,
|
||||
type=int,
|
||||
help='Number of access keys generated',
|
||||
)
|
||||
@click.option(
|
||||
'--random',
|
||||
is_flag=True,
|
||||
required=False,
|
||||
help='Interactive mode, ignores other keys'
|
||||
)
|
||||
@click.option(
|
||||
'--interactive',
|
||||
is_flag=True,
|
||||
required=False,
|
||||
help='Interactive mode, ignores other keys'
|
||||
)
|
||||
def access(id, count, interactive, random):
|
||||
if id and not count:
|
||||
keys = user_cursor.get_access_keys(user=id, count=1)
|
||||
links = user_cursor.gen_access_links(keys)
|
||||
user_cursor.echo_access_links(links)
|
||||
elif id and count:
|
||||
keys = user_cursor.get_access_keys(user=id, count=count)
|
||||
links = user_cursor.gen_access_links(keys)
|
||||
user_cursor.echo_access_links(links)
|
||||
elif interactive:
|
||||
pass
|
||||
elif random:
|
||||
admin = user_cursor.get_first_random_admin()
|
||||
keys = user_cursor.get_access_keys(user=admin.get('id', 3), count=1)
|
||||
links = user_cursor.gen_access_links(keys)
|
||||
user_cursor.echo_access_links(links)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
@user.command(help='Generate API token for mgrctl user')
|
||||
def token():
|
||||
token = user_cursor.gen_api_token()
|
||||
user_cursor.echo_api_token(token)
|
||||
|
@ -1,4 +1,8 @@
|
||||
from mgrctl.settings.platform import PLATFORM_TYPE
|
||||
from requests.packages import urllib3
|
||||
from mgrctl.settings.platform import (
|
||||
PLATFORM_TYPE,
|
||||
PLATFORM_VERIFY_SSL_WARNING
|
||||
)
|
||||
|
||||
# Name of nginx container:
|
||||
INPUT_HOSTNAME = 'input' if PLATFORM_TYPE == 'vm' else 'dci_input_1'
|
||||
@ -6,5 +10,16 @@ INPUT_HOSTNAME = 'input' if PLATFORM_TYPE == 'vm' else 'dci_input_1'
|
||||
# Port that nginx container is listening:
|
||||
INPUT_PORT = '1500'
|
||||
|
||||
# Internal API url:
|
||||
INPUT_URL = f'http://{INPUT_HOSTNAME}:{INPUT_PORT}'
|
||||
|
||||
# Headers for internal auth:
|
||||
HEADERS = {"Internal-Auth": "on", "Accept": "application/json"}
|
||||
|
||||
# Suppress warning from urllib3:
|
||||
if not PLATFORM_VERIFY_SSL_WARNING:
|
||||
# ! This is not recommended,
|
||||
# ! the user will not see a message about an untrusted SSL connection
|
||||
urllib3.disable_warnings(
|
||||
category=urllib3.exceptions.InsecureRequestWarning
|
||||
)
|
||||
|
@ -4,6 +4,9 @@ from mgrctl.utils.helpers import parse_json_file
|
||||
|
||||
PLATFORM_TYPE = env.str('PLATFORM_TYPE', 'vm')
|
||||
|
||||
PLATFORM_VERIFY_SSL = env.bool('PLATFORM_VERIFY_SSL', True)
|
||||
PLATFORM_VERIFY_SSL_WARNING = env.bool('PLATFORM_VERIFY_SSL_WARNING', True)
|
||||
|
||||
PLATFORM_CONFIG = env.str(
|
||||
'PLATFORM_CONFIG',
|
||||
f'/opt/ispsystem/{PLATFORM_TYPE}/config.json'
|
||||
@ -11,7 +14,20 @@ PLATFORM_CONFIG = env.str(
|
||||
|
||||
PLATFORM_CONFIG = parse_json_file(PLATFORM_CONFIG)
|
||||
|
||||
PLATFORM_URL = env.url(
|
||||
PLATFORM_URL = env.str(
|
||||
'PLATFORM_URL',
|
||||
f"https://{PLATFORM_CONFIG.get('DomainName' ,'replace.me')}"
|
||||
)
|
||||
|
||||
# Development mode:
|
||||
PLATFORM_DUMMY = env.bool('PLATFORM_DUMMY', False)
|
||||
|
||||
PLATFORM_DUMMY_VM6_API_URL = env.str('PLATFORM_DUMMY_VM6_API_URL', '')
|
||||
PLATFORM_DUMMY_VM6_EMAIL = env.str('PLATFORM_DUMMY_VM6_EMAIL', '')
|
||||
PLATFORM_DUMMY_VM6_PASSWORD = env.str('PLATFORM_DUMMY_VM6_PASSWORD', '')
|
||||
PLATFORM_DUMMY_VM6_TOKEN = env.str('PLATFORM_DUMMY_VM6_TOKEN', '')
|
||||
|
||||
PLATFORM_DUMMY_DCI6_API_URL = env.str('PLATFORM_DUMMY_DCI6_API_URL', '')
|
||||
PLATFORM_DUMMY_DCI6_EMAIL = env.str('PLATFORM_DUMMY_DCI6_EMAIL', '')
|
||||
PLATFORM_DUMMY_DCI6_PASSWORD = env.str('PLATFORM_DUMMY_DCI6_PASSWORD', '')
|
||||
PLATFORM_DUMMY_DCI6_TOKEN = env.str('PLATFORM_DUMMY_DCI6_TOKEN', '')
|
||||
|
74
mgrctl/utils/api_users.py
Normal file
74
mgrctl/utils/api_users.py
Normal file
@ -0,0 +1,74 @@
|
||||
import click
|
||||
from tabulate import tabulate
|
||||
|
||||
from mgrctl.settings.platform import PLATFORM_URL
|
||||
|
||||
|
||||
class UserAPI(object):
|
||||
def __init__(self, callback_class):
|
||||
"""Announces required parameters"""
|
||||
self.callback_class = callback_class
|
||||
self.callback = callback_class()
|
||||
|
||||
def get_users(self, role: str) -> dict:
|
||||
data = {}
|
||||
if role == 'admin':
|
||||
data = {"where": "((roles+CP+'%@admin%')+AND+(state+EQ+'active'))"}
|
||||
return self.callback.call_api(
|
||||
url='/user',
|
||||
method='GET',
|
||||
data=data
|
||||
)
|
||||
|
||||
def _format_users(self, users: dict) -> list:
|
||||
output = []
|
||||
for user in users.get('list', []):
|
||||
output.append({
|
||||
'id': user.get('id', ''),
|
||||
'email': user.get('email', ''),
|
||||
'roles': user.get('roles', []),
|
||||
'state': user.get('state', '')
|
||||
})
|
||||
return output
|
||||
|
||||
def get_first_random_admin(self):
|
||||
users = self.get_users(role='admin')
|
||||
admin = {}
|
||||
for user in users.get('list', []):
|
||||
if '@admin' in admin.get('roles', []):
|
||||
admin = user
|
||||
break
|
||||
return admin
|
||||
|
||||
def echo_users(self, role: str) -> None:
|
||||
users = self.get_users(role)
|
||||
output = self._format_users(users)
|
||||
click.echo(tabulate(output, headers='keys'))
|
||||
|
||||
def get_access_keys(self, user, count=1):
|
||||
keys = []
|
||||
while count >= 1:
|
||||
count -= 1
|
||||
key = self.callback.get_auth_key(user=user)
|
||||
check = key.get('key', '')
|
||||
if check:
|
||||
keys.append(key)
|
||||
return keys
|
||||
|
||||
def gen_access_links(self, keys: list) -> list:
|
||||
links = []
|
||||
for key in keys:
|
||||
_id = key.get('id', '')
|
||||
link = f"{PLATFORM_URL}/auth/key/{key.get('key', '')}"
|
||||
links.append({'id': _id, 'link': link})
|
||||
return links
|
||||
|
||||
def echo_access_links(self, links: list) -> None:
|
||||
click.echo(tabulate(links, headers='keys'))
|
||||
|
||||
def gen_api_token(self, email=None, password=None):
|
||||
token = self.callback.get_auth_token(email, password)
|
||||
return token
|
||||
|
||||
def echo_api_token(self, token: dict) -> None:
|
||||
click.echo(tabulate([token], headers='keys'))
|
Loading…
Reference in New Issue
Block a user