1
0
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:
Dain Nilsson 2013-05-07 17:25:26 +02:00
parent 79a0e719fa
commit 895de11057
6 changed files with 162 additions and 16 deletions

View File

@ -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
View 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()

View File

@ -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:

View File

@ -11,6 +11,10 @@ label {
font-weight: bold;
}
.input>span.help-block {
white-space: pre-line;
}
a {
color: #8bc53f;
}

View File

@ -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' %}

View File

@ -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)