mirror of
https://github.com/Yubico/yubiadmin.git
synced 2025-02-20 14:54:30 +01:00
Added YubiAuth app.
This commit is contained in:
parent
79a0e719fa
commit
895de11057
@ -29,7 +29,7 @@ from wtforms.fields import IntegerField, TextField, PasswordField
|
||||
from wtforms.widgets import PasswordInput
|
||||
from wtforms.validators import NumberRange, IPAddress
|
||||
from yubiadmin.util.app import App
|
||||
from yubiadmin.util.config import RegexHandler, FileConfig, parse_value
|
||||
from yubiadmin.util.config import python_handler, FileConfig
|
||||
from yubiadmin.util.form import ConfigForm
|
||||
from yubiadmin.util.system import invoke_rc_d
|
||||
|
||||
@ -38,14 +38,6 @@ __all__ = [
|
||||
]
|
||||
|
||||
|
||||
def python_handler(varname, default):
|
||||
pattern = r'(?sm)^\s*%s\s*=\s*(.*?)\s*$' % varname
|
||||
reader = lambda match: parse_value(match.group(1))
|
||||
writer = lambda x: '%s = %r' % (varname, str(x) if isinstance(x, unicode)
|
||||
else x)
|
||||
return RegexHandler(pattern, writer, reader, default=default)
|
||||
|
||||
|
||||
admin_config = FileConfig(
|
||||
'/etc/yubico/admin/yubiadmin.conf',
|
||||
[
|
||||
@ -97,6 +89,7 @@ class YubiAdmin(App):
|
||||
|
||||
def restart(self, request):
|
||||
invoke_rc_d('yubiadmin', 'restart')
|
||||
#We'll never get here, the user is unfortunately left with no response
|
||||
return self.redirect('/%s/general' % self.name)
|
||||
|
||||
|
||||
|
130
yubiadmin/apps/auth.py
Normal file
130
yubiadmin/apps/auth.py
Normal file
@ -0,0 +1,130 @@
|
||||
# Copyright (c) 2013 Yubico AB
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or
|
||||
# without modification, are permitted provided that the following
|
||||
# conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from wtforms.fields import SelectField, TextField, PasswordField, BooleanField
|
||||
from wtforms.widgets import PasswordInput
|
||||
from wtforms.validators import NumberRange, IPAddress
|
||||
from yubiadmin.util.app import App
|
||||
from yubiadmin.util.config import python_handler, FileConfig
|
||||
from yubiadmin.util.form import ConfigForm, FileForm
|
||||
|
||||
__all__ = [
|
||||
'app'
|
||||
]
|
||||
|
||||
AUTH_CONFIG_FILE = '/etc/yubico/auth/yubiauth.conf'
|
||||
|
||||
|
||||
auth_config = FileConfig(
|
||||
AUTH_CONFIG_FILE,
|
||||
[
|
||||
('client_id', python_handler('YKVAL_CLIENT_ID', 11004)),
|
||||
('client_secret', python_handler('YKVAL_CLIENT_SECRET',
|
||||
'5Vm3Zp2mUTQHMo1DeG9tdojpc1Y=')),
|
||||
('auto_provision', python_handler('AUTO_PROVISION', True)),
|
||||
('allow_empty', python_handler('ALLOW_EMPTY_PASSWORDS', False)),
|
||||
('security_level', python_handler('SECURITY_LEVEL', 1)),
|
||||
('yubikey_id', python_handler('YUBIKEY_IDENTIFICATION', False)),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class SecurityForm(ConfigForm):
|
||||
legend = 'Security'
|
||||
description = 'Security Settings for YubiAuth'
|
||||
config = auth_config
|
||||
|
||||
auto_provision = BooleanField(
|
||||
'Auto Provision YubiKeys',
|
||||
description="""
|
||||
When enabled, an attempt to authenticate a user that doesn't have a
|
||||
YubiKey assigned with a valid YubiKey OTP, will cause that YubiKey to
|
||||
become automatically assigned to the user.
|
||||
"""
|
||||
)
|
||||
yubikey_id = BooleanField(
|
||||
'Allow YubiKey Identification',
|
||||
description="""
|
||||
Allow users to authenticate using their YubiKey as identification,
|
||||
omitting the username.
|
||||
"""
|
||||
)
|
||||
allow_empty = BooleanField(
|
||||
'Allow Empty Passwords',
|
||||
description="""
|
||||
Allow users with no password to log in without providing a password.
|
||||
When set to False, a user with no password will be unable to log in.
|
||||
"""
|
||||
)
|
||||
security_level = SelectField(
|
||||
'Security Level',
|
||||
coerce=int,
|
||||
choices=[(0, 'Never'), (1, 'When Provisioned'), (2, 'Always')],
|
||||
description="""
|
||||
Defines who is required to provide a YubiKey OTP when logging in.
|
||||
The available levels are:
|
||||
Never - OTPs are not required to authenticate, by anyone.
|
||||
|
||||
When Provisioned - OTPs are required by all users that have a
|
||||
YubiKey assigned to them.
|
||||
|
||||
Always - OTPs are required by all users. If no YubiKey has been
|
||||
assigned, that user cannot log in, unless auto-provisioning is enabled.
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
class YubiAuth(App):
|
||||
"""
|
||||
YubiAuth
|
||||
|
||||
Web based configuration server.
|
||||
"""
|
||||
|
||||
name = 'auth'
|
||||
sections = ['general', 'advanced']
|
||||
|
||||
def general(self, request):
|
||||
"""
|
||||
General
|
||||
"""
|
||||
return self.render_forms(request,
|
||||
[SecurityForm()])
|
||||
|
||||
def advanced(self, request):
|
||||
"""
|
||||
Advanced
|
||||
"""
|
||||
return self.render_forms(request, [
|
||||
FileForm(AUTH_CONFIG_FILE, 'Configuration')
|
||||
])
|
||||
|
||||
#Pulls the tab to the right:
|
||||
advanced.advanced = True
|
||||
|
||||
|
||||
app = YubiAuth()
|
@ -39,6 +39,9 @@ __all__ = [
|
||||
]
|
||||
|
||||
|
||||
YKVAL_CONFIG_FILE = '/etc/yubico/val/ykval-config.php'
|
||||
|
||||
|
||||
def yk_pattern(varname, prefix='', suffix='', flags=None):
|
||||
regex = r'(?m)^(?!#)\$baseParams\[\'__YKVAL_%s__\'\]\s*=' \
|
||||
'\s*%s(.*?)%s\s*;\s*$' % (varname, prefix, suffix)
|
||||
@ -110,7 +113,7 @@ def is_daemon_running():
|
||||
|
||||
|
||||
ykval_config = FileConfig(
|
||||
'/etc/yubico/val/ykval-config.php',
|
||||
YKVAL_CONFIG_FILE,
|
||||
[
|
||||
('sync_default', yk_handler('SYNC_DEFAULT_LEVEL', 60)),
|
||||
('sync_secure', yk_handler('SYNC_SECURE_LEVEL', 40)),
|
||||
@ -252,7 +255,7 @@ class YubikeyVal(App):
|
||||
Advanced
|
||||
"""
|
||||
return self.render_forms(request, [
|
||||
FileForm('/etc/yubico/val/ykval-config.php', 'Configuration')
|
||||
FileForm(YKVAL_CONFIG_FILE, 'Configuration')
|
||||
])
|
||||
|
||||
#Pulls the tab to the right:
|
||||
|
@ -11,6 +11,10 @@ label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.input>span.help-block {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #8bc53f;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
{%- macro form_field_description(field) -%}
|
||||
{% if field.description %}
|
||||
<span class="help-block">{{ field.description }}</span>
|
||||
<span class="help-block">{{ field.description|trim }}</span>
|
||||
{% endif %}
|
||||
{%- endmacro -%}
|
||||
|
||||
@ -22,12 +22,12 @@
|
||||
|
||||
{%- macro form_field_boolean(field) -%}
|
||||
<div class="input">
|
||||
<label>
|
||||
<label class="checkbox">
|
||||
{{ field(**kwargs) }}
|
||||
<span>{{ field.label.text }}</span>
|
||||
{{ form_field_description(field) }}
|
||||
{{ form_field_errors(field) }}
|
||||
</label>
|
||||
{{ form_field_description(field) }}
|
||||
{{ form_field_errors(field) }}
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
<legend>{{ fieldset.legend }}</legend>
|
||||
{% endif %}
|
||||
{% if fieldset.description %}
|
||||
<p>{{ fieldset.description }}</p>
|
||||
<p>{{ fieldset.description|trim }}</p>
|
||||
{% endif %}
|
||||
{% for field in fieldset %}
|
||||
{% if field.type == 'HiddenField' %}
|
||||
|
@ -36,6 +36,7 @@ __all__ = [
|
||||
'FileConfig',
|
||||
'strip_comments',
|
||||
'php_inserter',
|
||||
'python_handler',
|
||||
'parse_block',
|
||||
'parse_value'
|
||||
]
|
||||
@ -60,6 +61,14 @@ def php_inserter(content, value):
|
||||
return content
|
||||
|
||||
|
||||
def python_handler(varname, default):
|
||||
pattern = r'(?sm)^\s*%s\s*=\s*(.*?)\s*$' % varname
|
||||
reader = lambda match: parse_value(match.group(1))
|
||||
writer = lambda x: '%s = %r' % (varname, str(x) if isinstance(x, unicode)
|
||||
else x)
|
||||
return RegexHandler(pattern, writer, reader, default=default)
|
||||
|
||||
|
||||
def strip_comments(text):
|
||||
def replacer(match):
|
||||
s = match.group(0)
|
||||
@ -100,6 +109,13 @@ def parse_value(valrepr):
|
||||
return float(valrepr)
|
||||
except ValueError:
|
||||
pass
|
||||
val_lower = valrepr.lower()
|
||||
if val_lower == 'true':
|
||||
return True
|
||||
elif val_lower == 'false':
|
||||
return False
|
||||
elif val_lower in ['none', 'null']:
|
||||
return None
|
||||
return strip_quotes(valrepr)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user