Unverified Commit 7e8f7343 authored by BaiJiangJie's avatar BaiJiangJie Committed by GitHub

Merge pull request #3033 from jumpserver/dev

Dev
parents b7915ccd 69841a41
...@@ -8,6 +8,7 @@ from django_auth_ldap.backend import _LDAPUser, LDAPBackend ...@@ -8,6 +8,7 @@ from django_auth_ldap.backend import _LDAPUser, LDAPBackend
from django_auth_ldap.config import _LDAPConfig, LDAPSearch, LDAPSearchUnion from django_auth_ldap.config import _LDAPConfig, LDAPSearch, LDAPSearchUnion
from users.utils import construct_user_email from users.utils import construct_user_email
from common.const import LDAP_AD_ACCOUNT_DISABLE
logger = _LDAPConfig.get_logger() logger = _LDAPConfig.get_logger()
...@@ -17,6 +18,15 @@ class LDAPAuthorizationBackend(LDAPBackend): ...@@ -17,6 +18,15 @@ class LDAPAuthorizationBackend(LDAPBackend):
Override this class to override _LDAPUser to LDAPUser Override this class to override _LDAPUser to LDAPUser
""" """
@staticmethod
def user_can_authenticate(user):
"""
Reject users with is_active=False. Custom user models that don't have
that attribute are allowed.
"""
is_valid = getattr(user, 'is_valid', None)
return is_valid or is_valid is None
def authenticate(self, request=None, username=None, password=None, **kwargs): def authenticate(self, request=None, username=None, password=None, **kwargs):
logger.info('Authentication LDAP backend') logger.info('Authentication LDAP backend')
if not username: if not username:
...@@ -25,34 +35,29 @@ class LDAPAuthorizationBackend(LDAPBackend): ...@@ -25,34 +35,29 @@ class LDAPAuthorizationBackend(LDAPBackend):
ldap_user = LDAPUser(self, username=username.strip(), request=request) ldap_user = LDAPUser(self, username=username.strip(), request=request)
user = self.authenticate_ldap_user(ldap_user, password) user = self.authenticate_ldap_user(ldap_user, password)
logger.info('Authenticate user: {}'.format(user)) logger.info('Authenticate user: {}'.format(user))
return user return user if self.user_can_authenticate(user) else None
def get_user(self, user_id): def get_user(self, user_id):
user = None user = None
try: try:
user = self.get_user_model().objects.get(pk=user_id) user = self.get_user_model().objects.get(pk=user_id)
LDAPUser(self, user=user) # This sets user.ldap_user LDAPUser(self, user=user) # This sets user.ldap_user
except ObjectDoesNotExist: except ObjectDoesNotExist:
pass pass
return user return user
def get_group_permissions(self, user, obj=None): def get_group_permissions(self, user, obj=None):
if not hasattr(user, 'ldap_user') and self.settings.AUTHORIZE_ALL_USERS: if not hasattr(user, 'ldap_user') and self.settings.AUTHORIZE_ALL_USERS:
LDAPUser(self, user=user) # This sets user.ldap_user LDAPUser(self, user=user) # This sets user.ldap_user
if hasattr(user, 'ldap_user'): if hasattr(user, 'ldap_user'):
permissions = user.ldap_user.get_group_permissions() permissions = user.ldap_user.get_group_permissions()
else: else:
permissions = set() permissions = set()
return permissions return permissions
def populate_user(self, username): def populate_user(self, username):
ldap_user = LDAPUser(self, username=username) ldap_user = LDAPUser(self, username=username)
user = ldap_user.populate_user() user = ldap_user.populate_user()
return user return user
...@@ -91,13 +96,19 @@ class LDAPUser(_LDAPUser): ...@@ -91,13 +96,19 @@ class LDAPUser(_LDAPUser):
for field, attr in self.settings.USER_ATTR_MAP.items(): for field, attr in self.settings.USER_ATTR_MAP.items():
try: try:
value = self.attrs[attr][0] value = self.attrs[attr][0]
if attr.lower() == 'useraccountcontrol' \
and field == 'is_active' and value:
value = int(value) & LDAP_AD_ACCOUNT_DISABLE \
!= LDAP_AD_ACCOUNT_DISABLE
except LookupError: except LookupError:
logger.warning("{} does not have a value for the attribute {}".format(self.dn, attr)) logger.warning("{} does not have a value for the attribute {}".format(self.dn, attr))
else: else:
if not hasattr(self._user, field): if not hasattr(self._user, field):
continue continue
if isinstance(getattr(self._user, field), bool): if isinstance(getattr(self._user, field), bool):
value = value.lower() in ['true', '1'] if isinstance(value, str):
value = value.lower()
value = value in ['true', '1', True]
setattr(self._user, field, value) setattr(self._user, field, value)
email = getattr(self._user, 'email', '') email = getattr(self._user, 'email', '')
......
...@@ -26,8 +26,8 @@ class BaseOpenIDAuthorizationBackend(object): ...@@ -26,8 +26,8 @@ class BaseOpenIDAuthorizationBackend(object):
Reject users with is_active=False. Custom user models that don't have Reject users with is_active=False. Custom user models that don't have
that attribute are allowed. that attribute are allowed.
""" """
is_active = getattr(user, 'is_active', None) is_valid = getattr(user, 'is_valid', None)
return is_active or is_active is None return is_valid or is_valid is None
def get_user(self, user_id): def get_user(self, user_id):
try: try:
......
from rest_framework.request import Request
from django.http.request import QueryDict from django.http.request import QueryDict
from django.conf import settings from django.conf import settings
from django.dispatch import receiver from django.dispatch import receiver
...@@ -52,14 +53,15 @@ def on_ldap_create_user(sender, user, ldap_user, **kwargs): ...@@ -52,14 +53,15 @@ def on_ldap_create_user(sender, user, ldap_user, **kwargs):
def generate_data(username, request): def generate_data(username, request):
if not request.user.is_anonymous and request.user.is_app: user_agent = request.META.get('HTTP_USER_AGENT', '')
if isinstance(request, Request):
login_ip = request.data.get('remote_addr', None) login_ip = request.data.get('remote_addr', None)
login_type = request.data.get('login_type', '') login_type = request.data.get('login_type', '')
user_agent = request.data.get('HTTP_USER_AGENT', '')
else: else:
login_ip = get_request_ip(request) login_ip = get_request_ip(request)
user_agent = request.META.get('HTTP_USER_AGENT', '')
login_type = 'W' login_type = 'W'
data = { data = {
'username': username, 'username': username,
'ip': login_ip, 'ip': login_ip,
......
...@@ -8,3 +8,7 @@ update_success_msg = _("%(name)s was updated successfully") ...@@ -8,3 +8,7 @@ update_success_msg = _("%(name)s was updated successfully")
FILE_END_GUARD = ">>> Content End <<<" FILE_END_GUARD = ">>> Content End <<<"
celery_task_pre_key = "CELERY_" celery_task_pre_key = "CELERY_"
KEY_CACHE_RESOURCES_ID = "RESOURCES_ID_{}" KEY_CACHE_RESOURCES_ID = "RESOURCES_ID_{}"
# AD User AccountDisable
# https://blog.csdn.net/bytxl/article/details/17763975
LDAP_AD_ACCOUNT_DISABLE = 2
...@@ -137,6 +137,16 @@ class PermissionsMixin(UserPassesTestMixin): ...@@ -137,6 +137,16 @@ class PermissionsMixin(UserPassesTestMixin):
return True return True
class UserCanUpdatePassword:
def has_permission(self, request, view):
return request.user.can_update_password()
class UserCanUpdateSSHKey:
def has_permission(self, request, view):
return request.user.can_update_ssh_key()
class NeedMFAVerify(permissions.BasePermission): class NeedMFAVerify(permissions.BasePermission):
def has_permission(self, request, view): def has_permission(self, request, view):
mfa_verify_time = request.session.get('MFA_VERIFY_TIME', 0) mfa_verify_time = request.session.get('MFA_VERIFY_TIME', 0)
......
...@@ -58,8 +58,8 @@ class JMSCSVRender(BaseRenderer): ...@@ -58,8 +58,8 @@ class JMSCSVRender(BaseRenderer):
template = request.query_params.get('template', 'export') template = request.query_params.get('template', 'export')
view = renderer_context['view'] view = renderer_context['view']
if isinstance(data, dict) and data.get("count"): if isinstance(data, dict):
data = data["results"] data = data.get("results", [])
if template == 'import': if template == 'import':
data = [data[0]] if data else data data = [data[0]] if data else data
......
This diff is collapsed.
...@@ -9,13 +9,15 @@ from rest_framework.generics import ( ...@@ -9,13 +9,15 @@ from rest_framework.generics import (
) )
from rest_framework.pagination import LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsValidUser, IsOrgAdminOrAppUser from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin
from common.tree import TreeNodeSerializer from common.tree import TreeNodeSerializer
from common.utils import get_logger from common.utils import get_logger
from ..utils import ( from ..utils import (
AssetPermissionUtil, ParserNode, AssetPermissionUtil, ParserNode,
) )
from .mixin import UserPermissionCacheMixin, GrantAssetsMixin, NodesWithUngroupMixin from .mixin import (
UserPermissionCacheMixin, GrantAssetsMixin, NodesWithUngroupMixin
)
from .. import const from .. import const
from ..hands import User, Asset, Node, SystemUser, NodeSerializer from ..hands import User, Asset, Node, SystemUser, NodeSerializer
from .. import serializers from .. import serializers
...@@ -29,6 +31,7 @@ __all__ = [ ...@@ -29,6 +31,7 @@ __all__ = [
'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi',
'ValidateUserAssetPermissionApi', 'UserGrantedNodesAsTreeApi', 'ValidateUserAssetPermissionApi', 'UserGrantedNodesAsTreeApi',
'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi', 'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi',
'RefreshAssetPermissionCacheApi'
] ]
...@@ -365,3 +368,12 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, RetrieveAPIView ...@@ -365,3 +368,12 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, RetrieveAPIView
actions = asset["system_users"].get(system_id, 0) actions = asset["system_users"].get(system_id, 0)
break break
return {"actions": actions} return {"actions": actions}
class RefreshAssetPermissionCacheApi(RetrieveAPIView):
permission_classes = (IsOrgAdmin,)
def retrieve(self, request, *args, **kwargs):
# expire all cache
AssetPermissionUtil.expire_all_cache()
return Response({'msg': True}, status=200)
...@@ -33,10 +33,14 @@ ...@@ -33,10 +33,14 @@
</div> </div>
</div> </div>
<div class="mail-box-header"> <div class="mail-box-header">
<div class="uc pull-left m-r-5"> <div class="btn-group uc pull-left m-r-5">
<a class="btn btn-sm btn-primary btn-create-permission"> <button class="btn btn-sm btn-primary btn-create-permission">
{% trans "Create permission" %} {% trans "Create permission" %}
</a> </button>
<button data-toggle="dropdown" class="btn btn-primary btn-sm dropdown-toggle"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a class="refresh-asset-permission-cache" href="#">{% trans 'Refresh permission cache' %}</a></li>
</ul>
</div> </div>
<table class="table table-striped table-bordered table-hover" id="permission_list_table" style="width: 100%"> <table class="table table-striped table-bordered table-hover" id="permission_list_table" style="width: 100%">
<thead> <thead>
...@@ -232,6 +236,14 @@ $(document).ready(function(){ ...@@ -232,6 +236,14 @@ $(document).ready(function(){
.replace('{{ DEFAULT_PK }}', uid); .replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url); objectDelete($this, name, the_url);
}) })
.on('click', '.refresh-asset-permission-cache', function () {
var the_url = "{% url 'api-perms:refresh-asset-permission-cache' %}";
requestApi({
url: the_url,
method: 'GET',
success_message: "{% trans 'Refresh success' %}"
});
})
.on('click', '.btn-create-permission', function () { .on('click', '.btn-create-permission', function () {
var url = "{% url 'perms:asset-permission-create' %}"; var url = "{% url 'perms:asset-permission-create' %}";
var nodes = zTree.getSelectedNodes(); var nodes = zTree.getSelectedNodes();
......
...@@ -57,6 +57,9 @@ asset_permission_urlpatterns = [ ...@@ -57,6 +57,9 @@ asset_permission_urlpatterns = [
# 验证用户是否有某个资产和系统用户的权限 # 验证用户是否有某个资产和系统用户的权限
path('asset-permissions/user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'), path('asset-permissions/user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'),
path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'), path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),
# 刷新缓存
path('asset-permissions/user/cache/refresh/', api.RefreshAssetPermissionCacheApi.as_view(), name='refresh-asset-permission-cache'),
] ]
......
...@@ -414,15 +414,12 @@ class AssetPermissionCacheMixin: ...@@ -414,15 +414,12 @@ class AssetPermissionCacheMixin:
cache.delete_pattern(key) cache.delete_pattern(key)
self.expire_cache_meta() self.expire_cache_meta()
@classmethod
def expire_all_cache_meta(cls):
key = cls.CACHE_META_KEY_PREFIX + '*'
cache.delete_pattern(key)
@classmethod @classmethod
def expire_all_cache(cls): def expire_all_cache(cls):
key = cls.CACHE_KEY_PREFIX + '*' key = cls.CACHE_KEY_PREFIX + '*'
cache.delete_pattern(key) cache.delete_pattern(key)
meta_key = cls.CACHE_META_KEY_PREFIX + '*'
cache.delete_pattern(meta_key)
class AssetPermissionUtil(AssetPermissionCacheMixin): class AssetPermissionUtil(AssetPermissionCacheMixin):
......
...@@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
from users.models import User from users.models import User
from users.utils import construct_user_email from users.utils import construct_user_email
from common.utils import get_logger from common.utils import get_logger
from common.const import LDAP_AD_ACCOUNT_DISABLE
from .models import settings from .models import settings
...@@ -70,7 +71,12 @@ class LDAPUtil: ...@@ -70,7 +71,12 @@ class LDAPUtil:
for attr, mapping in self.attr_map.items(): for attr, mapping in self.attr_map.items():
if not hasattr(entry, mapping): if not hasattr(entry, mapping):
continue continue
user_item[attr] = getattr(entry, mapping).value or '' value = getattr(entry, mapping).value or ''
if mapping.lower() == 'useraccountcontrol' and attr == 'is_active'\
and value:
value = int(value) & LDAP_AD_ACCOUNT_DISABLE \
!= LDAP_AD_ACCOUNT_DISABLE
user_item[attr] = value
return user_item return user_item
def search_user_items(self): def search_user_items(self):
...@@ -102,7 +108,9 @@ class LDAPUtil: ...@@ -102,7 +108,9 @@ class LDAPUtil:
if not hasattr(user, field): if not hasattr(user, field):
continue continue
if isinstance(getattr(user, field), bool): if isinstance(getattr(user, field), bool):
value = value.lower() in ['true', 1] if isinstance(value, str):
value = value.lower()
value = value in ['true', 1, True]
setattr(user, field, value) setattr(user, field, value)
user.save() user.save()
......
...@@ -157,7 +157,7 @@ UserProfileForm.verbose_name = _("Profile") ...@@ -157,7 +157,7 @@ UserProfileForm.verbose_name = _("Profile")
class UserMFAForm(forms.ModelForm): class UserMFAForm(forms.ModelForm):
mfa_description = _( mfa_description = _(
'Tip: when enabled, ' 'When enabled, '
'you will enter the MFA binding process the next time you log in. ' 'you will enter the MFA binding process the next time you log in. '
'you can also directly bind in ' 'you can also directly bind in '
'"personal information -> quick modification -> change MFA Settings"!') '"personal information -> quick modification -> change MFA Settings"!')
......
...@@ -54,6 +54,9 @@ class AuthMixin: ...@@ -54,6 +54,9 @@ class AuthMixin:
def can_update_password(self): def can_update_password(self):
return self.is_local return self.is_local
def can_update_ssh_key(self):
return self.is_local
def check_otp(self, code): def check_otp(self, code):
from ..utils import check_otp_code from ..utils import check_otp_code
return check_otp_code(self.otp_secret_key, code) return check_otp_code(self.otp_secret_key, code)
......
...@@ -73,14 +73,17 @@ ...@@ -73,14 +73,17 @@
<p id="noTerms" class="red-fonts" style="visibility: hidden; font-size: 10px; margin-top: 10px;">* {% trans 'Please choose the terms and conditions.' %}</p> <p id="noTerms" class="red-fonts" style="visibility: hidden; font-size: 10px; margin-top: 10px;">* {% trans 'Please choose the terms and conditions.' %}</p>
{% endif %} {% endif %}
{% bootstrap_form wizard.form %} {% if wizard.steps.current == '1' and not request.user.can_update_ssh_key %}
<b id="ssh_key_help_text">{% trans 'User auth from {}, ssh key login is not supported' %}</b>
{% else %}
{% bootstrap_form wizard.form %}
{% endif %}
{% if form.mfa_description %} {% if form.mfa_description %}
<b>{{ form.mfa_description }}</b> <b>{{ form.mfa_description }}</b>
{% endif %} {% endif %}
{% if form.pubkey_description %} {% if form.pubkey_description and request.user.can_update_ssh_key %}
<span>或者:</span>
<a type="button" id="btn-reset-pubkey">{{ form.pubkey_description }}</a> <a type="button" id="btn-reset-pubkey">{{ form.pubkey_description }}</a>
{% endif %} {% endif %}
...@@ -121,26 +124,33 @@ ...@@ -121,26 +124,33 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
$(document).on('click', ".fl_goto", function(){ $(document).ready(function(){
var $form = $('#fl_form'); var origin_ssh_key_text = $("#ssh_key_help_text").text();
$('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form); var new_ssh_key_text = origin_ssh_key_text.replace('{}', "{{ request.user.source_display }}");
$form.submit(); $("#ssh_key_help_text").html(new_ssh_key_text)
return false; })
}).on('click', '#fl_submit', function(){ .on('click', ".fl_goto", function(){
var isFinish = $('#fl_submit').html() === "{% trans 'Finish' %}"; var $form = $('#fl_form');
var noChecked = !$('#acceptTerms').prop('checked'); $('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form);
if ( isFinish && noChecked){ $form.submit();
$('#noTerms').css('visibility', 'visible'); return false;
} })
else{ .on('click', '#fl_submit', function(){
$('#fl_form').submit(); var isFinish = $('#fl_submit').html() === "{% trans 'Finish' %}";
return false; var noChecked = !$('#acceptTerms').prop('checked');
} if ( isFinish && noChecked){
}).on('click', '#btn-reset-pubkey', function () { $('#noTerms').css('visibility', 'visible');
var the_url = '{% url "users:user-pubkey-generate" %}'; }
window.open(the_url, "_blank"); else{
$('#fl_form').submit(); $('#fl_form').submit();
}) return false;
}
})
.on('click', '#btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank");
$('#fl_form').submit();
})
</script> </script>
{% endblock %} {% endblock %}
...@@ -119,10 +119,12 @@ ...@@ -119,10 +119,12 @@
<td>{% trans 'Last login' %}:</td> <td>{% trans 'Last login' %}:</td>
<td><b>{{ user_object.last_login|date:"Y-m-j H:i:s" }}</b></td> <td><b>{{ user_object.last_login|date:"Y-m-j H:i:s" }}</b></td>
</tr> </tr>
{% if user_object.can_update_password %}
<tr> <tr>
<td>{% trans 'Last password updated' %}:</td> <td>{% trans 'Last password updated' %}:</td>
<td><b>{{ user_object.date_password_last_updated|date:"Y-m-j H:i:s" }}</b></td> <td><b>{{ user_object.date_password_last_updated|date:"Y-m-j H:i:s" }}</b></td>
</tr> </tr>
{% endif %}
<tr> <tr>
<td>{% trans 'Comment' %}:</td> <td>{% trans 'Comment' %}:</td>
<td><b>{{ user_object.comment }}</b></td> <td><b>{{ user_object.comment }}</b></td>
...@@ -187,6 +189,7 @@ ...@@ -187,6 +189,7 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if user_object.can_update_ssh_key %}
<tr> <tr>
<td>{% trans 'Send reset ssh key mail' %}:</td> <td>{% trans 'Send reset ssh key mail' %}:</td>
<td> <td>
...@@ -195,6 +198,7 @@ ...@@ -195,6 +198,7 @@
</span> </span>
</td> </td>
</tr> </tr>
{% endif %}
<tr style="{% if not unblock %}display:none{% endif %}"> <tr style="{% if not unblock %}display:none{% endif %}">
<td>{% trans 'Unblock user' %}</td> <td>{% trans 'Unblock user' %}</td>
<td> <td>
......
...@@ -39,12 +39,16 @@ ...@@ -39,12 +39,16 @@
<li> <li>
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a> <a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
</li> </li>
{% if request.user.can_update_password %}
<li class="active"> <li class="active">
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a> <a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
</li> </li>
{% endif %}
{% if request.user.can_update_ssh_key %}
<li> <li>
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a> <a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="tab-content" style="background-color: #ffffff"> <div class="tab-content" style="background-color: #ffffff">
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
<td>{{ user.is_active|yesno:"Yes,No,Unkown" }}</td> <td>{{ user.is_active|yesno:"Yes,No,Unkown" }}</td>
</tr> </tr>
{% if user.can_update_ssh_key %}
<tr> <tr>
<td class="text-navy">{% trans 'Public key' %}</td> <td class="text-navy">{% trans 'Public key' %}</td>
<td> <td>
...@@ -81,6 +82,7 @@ ...@@ -81,6 +82,7 @@
</table> </table>
</td> </td>
</tr> </tr>
{% endif %}
<tr> <tr>
<td class="text-navy">{% trans 'MFA certification' %}</td> <td class="text-navy">{% trans 'MFA certification' %}</td>
<td> <td>
...@@ -108,10 +110,12 @@ ...@@ -108,10 +110,12 @@
<td class="text-navy">{% trans 'Last login' %}</td> <td class="text-navy">{% trans 'Last login' %}</td>
<td>{{ user.last_login|date:"Y-m-d H:i:s" }}</td> <td>{{ user.last_login|date:"Y-m-d H:i:s" }}</td>
</tr> </tr>
{% if user.can_update_password %}
<tr> <tr>
<td class="text-navy">{% trans 'Last password updated' %}</td> <td class="text-navy">{% trans 'Last password updated' %}</td>
<td>{{ user.date_password_last_updated|date:"Y-m-d H:i:s" }}</td> <td>{{ user.date_password_last_updated|date:"Y-m-d H:i:s" }}</td>
</tr> </tr>
{% endif %}
<tr> <tr>
<td class="text-navy">{% trans 'Date expired' %}</td> <td class="text-navy">{% trans 'Date expired' %}</td>
<td>{{ user.date_expired|date:"Y-m-d H:i:s" }}</td> <td>{{ user.date_expired|date:"Y-m-d H:i:s" }}</td>
...@@ -189,6 +193,7 @@ ...@@ -189,6 +193,7 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if request.user.can_update_ssh_key %}
<tr> <tr>
<td>{% trans 'Update SSH public key' %}:</td> <td>{% trans 'Update SSH public key' %}:</td>
<td> <td>
...@@ -205,6 +210,7 @@ ...@@ -205,6 +210,7 @@
</span> </span>
</td> </td>
</tr> </tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
......
...@@ -36,12 +36,16 @@ ...@@ -36,12 +36,16 @@
<li class="active"> <li class="active">
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a> <a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
</li> </li>
{% if request.user.can_update_password %}
<li> <li>
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a> <a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
</li> </li>
{% endif %}
{% if request.user.can_update_ssh_key %}
<li> <li>
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a> <a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="tab-content" style="background-color: #ffffff"> <div class="tab-content" style="background-color: #ffffff">
......
...@@ -36,12 +36,16 @@ ...@@ -36,12 +36,16 @@
<li> <li>
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a> <a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
</li> </li>
{% if request.user.can_update_password %}
<li> <li>
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a> <a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
</li> </li>
{% endif %}
{% if request.user.can_update_ssh_key %}
<li class="active"> <li class="active">
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a> <a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="tab-content" style="background-color: #ffffff"> <div class="tab-content" style="background-color: #ffffff">
......
...@@ -23,7 +23,16 @@ ...@@ -23,7 +23,16 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if object.can_update_ssh_key %}
{% bootstrap_field form.public_key layout="horizontal" %} {% bootstrap_field form.public_key layout="horizontal" %}
{% else %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'ssh public key' %}</label>
<div class="col-sm-8 controls" style="margin-top: 8px;" id="ssh_key_help_text">
{% trans 'User auth from {}, ssh key login is not supported' %}
</div>
</div>
{% endif %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
...@@ -77,9 +86,13 @@ function passwordCheck() { ...@@ -77,9 +86,13 @@ function passwordCheck() {
$(document).ready(function(){ $(document).ready(function(){
passwordCheck(); passwordCheck();
var origin_text = $("#password_help_text").text(); var origin_password_text = $("#password_help_text").text();
var new_text = origin_text.replace('{}', "{{ object.source_display }}"); var new_password_text = origin_password_text.replace('{}', "{{ object.source_display }}");
$("#password_help_text").html(new_text); $("#password_help_text").html(new_password_text);
var origin_ssh_key_text = $("#ssh_key_help_text").text();
var new_ssh_key_text = origin_ssh_key_text.replace('{}', "{{ object.source_display }}");
$("#ssh_key_help_text").html(new_ssh_key_text)
}) })
.on("submit", "form", function (evt) { .on("submit", "form", function (evt) {
......
...@@ -198,7 +198,7 @@ def check_user_valid(**kwargs): ...@@ -198,7 +198,7 @@ def check_user_valid(**kwargs):
if password and authenticate(username=username, password=password): if password and authenticate(username=username, password=password):
return user, '' return user, ''
if public_key and user.public_key: if public_key and user.public_key and user.is_local:
public_key_saved = user.public_key.split() public_key_saved = user.public_key.split()
if len(public_key_saved) == 1: if len(public_key_saved) == 1:
if public_key == public_key_saved[0]: if public_key == public_key_saved[0]:
......
...@@ -2,40 +2,32 @@ ...@@ -2,40 +2,32 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json
import uuid
import csv
import codecs
import chardet
from io import StringIO
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import authenticate, login as auth_login from django.contrib.auth import authenticate
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.cache import cache from django.core.cache import cache
from django.conf import settings from django.conf import settings
from django.http import HttpResponse, JsonResponse from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy, reverse
from django.utils import timezone
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.decorators import method_decorator
from django.views import View from django.views import View
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.db import transaction
from django.views.generic.edit import ( from django.views.generic.edit import (
CreateView, UpdateView, FormView CreateView, UpdateView, FormView
) )
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import logout as auth_logout from django.contrib.auth import logout as auth_logout
from common.const import ( from common.const import (
create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID
) )
from common.mixins import JSONResponseMixin from common.utils import get_logger, ssh_key_gen
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen from common.permissions import (
from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser PermissionsMixin, IsOrgAdmin, IsValidUser,
UserCanUpdatePassword, UserCanUpdateSSHKey,
)
from orgs.utils import current_org from orgs.utils import current_org
from .. import forms from .. import forms
from ..models import User, UserGroup from ..models import User, UserGroup
...@@ -260,6 +252,7 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView): ...@@ -260,6 +252,7 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView):
model = User model = User
form_class = forms.UserPasswordForm form_class = forms.UserPasswordForm
success_url = reverse_lazy('users:user-profile') success_url = reverse_lazy('users:user-profile')
permission_classes = [IsValidUser, UserCanUpdatePassword]
def get_object(self, queryset=None): def get_object(self, queryset=None):
return self.request.user return self.request.user
...@@ -279,12 +272,6 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView): ...@@ -279,12 +272,6 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView):
return super().get_success_url() return super().get_success_url()
def form_valid(self, form): def form_valid(self, form):
if not self.request.user.can_update_password():
error = _("User auth from {}, go there change password").format(
self.request.source_display
)
form.add_error("password", error)
return self.form_invalid(form)
password = form.cleaned_data.get('new_password') password = form.cleaned_data.get('new_password')
is_ok = check_password_rules(password) is_ok = check_password_rules(password)
if not is_ok: if not is_ok:
...@@ -300,7 +287,7 @@ class UserPublicKeyUpdateView(PermissionsMixin, UpdateView): ...@@ -300,7 +287,7 @@ class UserPublicKeyUpdateView(PermissionsMixin, UpdateView):
template_name = 'users/user_pubkey_update.html' template_name = 'users/user_pubkey_update.html'
model = User model = User
form_class = forms.UserPublicKeyForm form_class = forms.UserPublicKeyForm
permission_classes = [IsValidUser] permission_classes = [IsValidUser, UserCanUpdateSSHKey]
success_url = reverse_lazy('users:user-profile') success_url = reverse_lazy('users:user-profile')
def get_object(self, queryset=None): def get_object(self, queryset=None):
......
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