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
|
#!/usr/bin/env python3
# Copyright 2017, 2022 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import vyos.opmode
from jinja2 import Template
from vyos.configquery import ConfigTreeQuery
from vyos.xml import defaults
from vyos.configdict import dict_merge
from vyos.utils.process import popen
users_otp_template = Template("""
{% if info == "full" %}
# You can share it with the user, he just needs to scan the QR in his OTP app
# username: {{username}}
# OTP KEY: {{key_base32}}
# OTP URL: {{otp_url}}
{{qrcode}}
# To add this OTP key to configuration, run the following commands:
set system login user {{username}} authentication otp key '{{key_base32}}'
{% if rate_limit != "3" %}
set system login user {{username}} authentication otp rate-limit '{{rate_limit}}'
{% endif %}
{% if rate_time != "30" %}
set system login user {{username}} authentication otp rate-time '{{rate_time}}'
{% endif %}
{% if window_size != "3" %}
set system login user {{username}} authentication otp window-size '{{window_size}}'
{% endif %}
{% elif info == "key-b32" %}
# OTP key in Base32 for system user {{username}}:
{{key_base32}}
{% elif info == "qrcode" %}
# QR code for system user '{{username}}'
{{qrcode}}
{% elif info == "uri" %}
# URI for system user '{{username}}'
{{otp_url}}
{% endif %}
""", trim_blocks=True, lstrip_blocks=True)
def _check_uname_otp(username:str):
"""
Check if "username" exists and have an OTP key
"""
config = ConfigTreeQuery()
base_key = ['system', 'login', 'user', username, 'authentication', 'otp', 'key']
if not config.exists(base_key):
return None
return True
def _get_login_otp(username: str, info:str):
"""
Retrieve user settings from configuration and set some defaults
"""
config = ConfigTreeQuery()
base = ['system', 'login', 'user', username]
if not config.exists(base):
return None
user_otp = config.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
default_values = defaults(['system', 'login', 'user'])
user_otp = dict_merge(default_values, user_otp)
result = user_otp['authentication']['otp']
# Filling in the system and default options
result['info'] = info
result['hostname'] = os.uname()[1]
result['username'] = username
result['key_base32'] = result['key']
result['otp_length'] = '6'
result['interval'] = '30'
result['token_type'] = 'hotp-time'
if result['token_type'] == 'hotp-time':
token_type_acrn = 'totp'
result['otp_url'] = ''.join(["otpauth://",token_type_acrn,"/",username,"@",\
result['hostname'],"?secret=",result['key_base32'],"&digits=",\
result['otp_length'],"&period=",result['interval']])
result['qrcode'],err = popen('qrencode -t ansiutf8', input=result['otp_url'])
return result
def show_login(raw: bool, username: str, info:str):
'''
Display OTP parameters for <username>
'''
check_otp = _check_uname_otp(username)
if check_otp:
user_otp_params = _get_login_otp(username, info)
else:
print(f'There is no such user ("{username}") with an OTP key configured')
print('You can use the following command to generate a key for a user:\n')
print(f'generate system login username {username} otp-key hotp-time')
sys.exit(0)
if raw:
return user_otp_params
return users_otp_template.render(user_otp_params)
if __name__ == '__main__':
try:
res = vyos.opmode.run(sys.modules[__name__])
if res:
print(res)
except (ValueError, vyos.opmode.Error) as e:
print(e)
sys.exit(1)
|