-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
login: T4754: show configured 2FA OTP key
- Loading branch information
Showing
3 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2017, 2022 VyOS maintainers and contributors <[email protected]> | ||
# | ||
# 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.util 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) |