Commit c9ee8ede authored by ibuler's avatar ibuler

[Update] 修改mfa

parent bfd8a9c6
......@@ -31,11 +31,11 @@
<div class="form-group">
<div class="col-sm-9 col-lg-9 col-sm-offset-2">
<div class="checkbox checkbox-success">
<input type="checkbox" name="enable_otp" checked id="id_enable_otp"><label for="id_enable_otp">{% trans 'Enable-MFA' %}</label>
<input type="checkbox" name="enable_mfa" checked id="id_enable_mfa"><label for="id_enable_mfa">{% trans 'Enable-MFA' %}</label>
</div>
</div>
</div>
</form>
{% endblock %}
{% block modal_confirm_id %}btn_asset_group_bulk_update{% endblock %}
\ No newline at end of file
{% block modal_confirm_id %}btn_asset_group_bulk_update{% endblock %}
......@@ -128,7 +128,7 @@ def generate_data(username, request):
def on_user_auth_success(sender, user, request, **kwargs):
logger.debug('User login success: {}'.format(user.username))
data = generate_data(user.username, request)
data.update({'mfa': int(user.otp_enabled), 'status': True})
data.update({'mfa': int(user.mfa_enabled), 'status': True})
write_login_log_async.delay(**data)
......
......@@ -89,7 +89,9 @@ class AuthMixin:
def check_user_mfa_if_need(self, user):
if self.request.session.get('auth_mfa'):
return
if not user.otp_enabled or not user.otp_secret_key:
if not user.mfa_enabled:
return
if not user.otp_secret_key and user.mfa_is_otp():
return
raise errors.MFARequiredError()
......
......@@ -130,8 +130,8 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
auth_login(self.request, user)
self.send_auth_signal(success=True, user=user)
self.clear_auth_mark()
# 启用但是没有设置otp
if user.otp_enabled and not user.otp_secret_key:
# 启用但是没有设置otp, 排除radius
if user.mfa_enabled_but_not_set():
# 1,2,mfa_setting & F
return reverse('users:user-otp-enable-authentication')
url = redirect_user_first_login_or_index(
......
......@@ -172,7 +172,7 @@ class UserResetOTPApi(UserQuerysetMixin, generics.RetrieveAPIView):
if user == request.user:
msg = _("Could not reset self otp, use profile reset instead")
return Response({"error": msg}, status=401)
if user.otp_enabled and user.otp_secret_key:
if user.mfa_enabled and user.otp_secret_key:
user.otp_secret_key = ''
user.save()
logout(request)
......
......@@ -61,10 +61,10 @@ class UserCreateUpdateFormMixin(OrgModelForm):
fields = [
'username', 'name', 'email', 'groups', 'wechat',
'source', 'phone', 'role', 'date_expired',
'comment', 'otp_level'
'comment', 'mfa_level'
]
widgets = {
'otp_level': forms.RadioSelect(),
'mfa_level': forms.RadioSelect(),
'groups': forms.SelectMultiple(
attrs={
'class': 'select2',
......@@ -126,13 +126,13 @@ class UserCreateUpdateFormMixin(OrgModelForm):
def save(self, commit=True):
password = self.cleaned_data.get('password')
otp_level = self.cleaned_data.get('otp_level')
mfa_level = self.cleaned_data.get('mfa_level')
public_key = self.cleaned_data.get('public_key')
user = super().save(commit=commit)
if password:
user.reset_password(password)
if otp_level:
user.otp_level = otp_level
if mfa_level:
user.mfa_level = mfa_level
user.save()
if public_key:
user.public_key = public_key
......@@ -183,10 +183,10 @@ class UserMFAForm(forms.ModelForm):
class Meta:
model = User
fields = ['otp_level']
widgets = {'otp_level': forms.RadioSelect()}
fields = ['mfa_level']
widgets = {'mfa_level': forms.RadioSelect()}
help_texts = {
'otp_level': _('* Enable MFA authentication '
'mfa_level': _('* Enable MFA authentication '
'to make the account more secure.'),
}
......
# Generated by Django 2.2.5 on 2019-11-18 08:12
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('users', '0023_auto_20190724_1525'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='otp_level',
new_name='mfa_level',
),
]
......@@ -346,35 +346,41 @@ class TokenMixin:
class MFAMixin:
otp_level = 0
mfa_level = 0
otp_secret_key = ''
OTP_LEVEL_CHOICES = (
MFA_LEVEL_CHOICES = (
(0, _('Disable')),
(1, _('Enable')),
(2, _("Force enable")),
)
@property
def otp_enabled(self):
return self.otp_force_enabled or self.otp_level > 0
def mfa_enabled(self):
return self.mfa_force_enabled or self.mfa_level > 0
@property
def otp_force_enabled(self):
def mfa_force_enabled(self):
if settings.SECURITY_MFA_AUTH:
return True
return self.otp_level == 2
return self.mfa_level == 2
def enable_otp(self):
if not self.otp_level == 2:
self.otp_level = 1
def enable_mfa(self):
if not self.mfa_level == 2:
self.mfa_level = 1
def force_enable_otp(self):
self.otp_level = 2
def force_enable_mfa(self):
self.mfa_level = 2
def disable_otp(self):
self.otp_level = 0
def disable_mfa(self):
self.mfa_level = 0
self.otp_secret_key = None
@staticmethod
def mfa_is_otp():
if settings.CONFIG.OTP_IN_RADIUS:
return False
return True
def check_otp_on_radius(self, code):
from authentication.backends.radius import RadiusBackend
backend = RadiusBackend()
......@@ -390,6 +396,11 @@ class MFAMixin:
else:
return check_otp_code(self.otp_secret_key, code)
def mfa_enabled_but_not_set(self):
if self.mfa_enabled and self.mfa_is_otp() and not self.otp_secret_key:
return True
return False
class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
SOURCE_LOCAL = 'local'
......@@ -428,8 +439,8 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
phone = models.CharField(
max_length=20, blank=True, null=True, verbose_name=_('Phone')
)
otp_level = models.SmallIntegerField(
default=0, choices=MFAMixin.OTP_LEVEL_CHOICES, verbose_name=_('MFA')
mfa_level = models.SmallIntegerField(
default=0, choices=MFAMixin.MFA_LEVEL_CHOICES, verbose_name=_('MFA')
)
otp_secret_key = fields.EncryptCharField(max_length=128, blank=True, null=True)
# Todo: Auto generate key, let user download
......
......@@ -27,7 +27,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
fields = [
'id', 'name', 'username', 'password', 'email', 'public_key',
'groups', 'groups_display',
'role', 'role_display', 'wechat', 'phone', 'otp_level',
'role', 'role_display', 'wechat', 'phone', 'mfa_level',
'comment', 'source', 'source_display', 'is_valid', 'is_expired',
'is_active', 'created_by', 'is_first_login',
'date_password_last_updated', 'date_expired', 'avatar_url',
......
......@@ -20,7 +20,7 @@
<h3>{% trans 'Auth' %}</h3>
{% block password %}{% endblock %}
{% bootstrap_field form.otp_level layout="horizontal" %}
{% bootstrap_field form.mfa_level layout="horizontal" %}
{% bootstrap_field form.source layout="horizontal" %}
<div class="hr-line-dashed"></div>
......@@ -77,7 +77,7 @@
$(document).ready(function () {
$('.select2').select2();
initDateRangePicker('#id_date_expired');
var mfa_radio = $('#id_otp_level');
var mfa_radio = $('#id_mfa_level');
mfa_radio.addClass("form-inline");
mfa_radio.children().css("margin-right","15px");
fieldDisplay()
......
......@@ -91,9 +91,9 @@
<tr>
<td>{% trans 'MFA certification' %}:</td>
<td><b>
{% if user_object.otp_force_enabled %}
{% if user_object.mfa_force_enabled %}
{% trans 'Force enabled' %}
{% elif user_object.otp_enabled%}
{% elif user_object.mfa_enabled%}
{% trans 'Enabled' %}
{% else %}
{% trans 'Disabled' %}
......@@ -162,9 +162,9 @@
<td><span class="pull-right">
<div class="switch">
<div class="onoffswitch">
<input type="checkbox" class="onoffswitch-checkbox" {% if user_object.otp_force_enabled %} checked {% endif %}
id="force_enable_otp">
<label class="onoffswitch-label" for="force_enable_otp">
<input type="checkbox" class="onoffswitch-checkbox" {% if user_object.mfa_force_enabled %} checked {% endif %}
id="force_enable_mfa">
<label class="onoffswitch-label" for="force_enable_mfa">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
......@@ -370,7 +370,7 @@ $(document).ready(function() {
success_message: success
});
})
.on('click', '#force_enable_otp', function() {
.on('click', '#force_enable_mfa', function() {
{% if request.user == user_object %}
toastr.error("{% trans 'Goto profile page enable MFA' %}");
return;
......@@ -378,16 +378,16 @@ $(document).ready(function() {
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
var checked = $(this).prop('checked');
var otp_level;
var mfa_level;
var otp_secret_key;
if(checked){
otp_level = 2
mfa_level = 2
}else{
otp_level = 0;
mfa_level = 0;
otp_secret_key = '';
}
var body = {
'otp_level': otp_level,
'mfa_level': mfa_level,
'otp_secret_key': otp_secret_key
};
var success = '{% trans "Update successfully!" %}';
......
......@@ -86,9 +86,9 @@
<tr>
<td class="text-navy">{% trans 'MFA certification' %}</td>
<td>
{% if user.otp_force_enabled %}
{% if user.mfa_force_enabled %}
{% trans 'Force enable' %}
{% elif user.otp_enabled%}
{% elif user.mfa_enabled%}
{% trans 'Enable' %}
{% else %}
{% trans 'Disable' %}
......@@ -158,8 +158,8 @@
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" id=""
href="
{% if request.user.otp_enabled and request.user.otp_secret_key %}
{% if request.user.otp_force_enabled %}
{% if request.user.mfa_enabled and request.user.otp_secret_key %}
{% if request.user.mfa_force_enabled %}
" disabled >{% trans 'Disable' %}
{% else %}
{% url 'users:user-otp-disable-authentication' %}
......@@ -183,7 +183,7 @@
</td>
</tr>
{% endif %}
{% if request.user.otp_enabled and request.user.otp_secret_key %}
{% if request.user.mfa_enabled and request.user.otp_secret_key %}
<tr>
<td>{% trans 'Update MFA' %}:</td>
<td>
......
......@@ -171,12 +171,12 @@ class UserFirstLoginView(PermissionsMixin, SessionWizardView):
form.instance = self.request.user
if isinstance(form, forms.UserMFAForm):
choices = form.fields["otp_level"].choices
if self.request.user.otp_force_enabled:
choices = form.fields["mfa_level"].choices
if self.request.user.mfa_force_enabled:
choices = [(k, v) for k, v in choices if k == 2]
else:
choices = [(k, v) for k, v in choices if k in [0, 1]]
form.fields["otp_level"].choices = choices
form.fields["otp_level"].initial = self.request.user.otp_level
form.fields["mfa_level"].choices = choices
form.fields["mfa_level"].initial = self.request.user.mfa_level
return form
......@@ -347,7 +347,12 @@ class UserOtpEnableAuthenticationView(FormView):
if not user:
form.add_error("password", _("Password invalid"))
return self.form_invalid(form)
return redirect(self.get_success_url())
if user.mfa_is_otp():
return redirect(self.get_success_url())
else:
user.enable_mfa()
user.save()
return redirect('users:user-otp-settings-success')
def get_success_url(self):
return reverse('users:user-otp-enable-install-app')
......@@ -395,7 +400,7 @@ class UserOtpEnableBindView(TemplateView, FormView):
def save_otp(self, otp_secret_key):
user = get_user_or_tmp_user(self.request)
user.enable_otp()
user.enable_mfa()
user.otp_secret_key = otp_secret_key
user.save()
......@@ -411,7 +416,7 @@ class UserOtpDisableAuthenticationView(FormView):
otp_secret_key = user.otp_secret_key
if check_otp_code(otp_secret_key, otp_code):
user.disable_otp()
user.disable_mfa()
user.save()
return super().form_valid(form)
else:
......@@ -447,7 +452,7 @@ class UserOtpSettingsSuccessView(TemplateView):
auth_logout(self.request)
title = _('MFA enable success')
describe = _('MFA enable success, return login page')
if not user.otp_enabled:
if not user.mfa_enabled:
title = _('MFA disable success')
describe = _('MFA disable success, return login page')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment