Commit 25cb47d2 authored by ibuler's avatar ibuler

[Change] 拆分user view为多个view

parent 87bbb6af
......@@ -14,8 +14,9 @@ class TerminalSerializer(serializers.ModelSerializer):
class Meta:
model = Terminal
fields = ['id', 'name', 'remote_addr', 'type', 'url', 'comment', 'is_accepted',
'is_active', 'get_type_display', 'proxy_online', 'is_alive']
fields = ['id', 'name', 'remote_addr', 'type', 'url', 'comment',
'is_accepted', 'is_active', 'get_type_display',
'proxy_online', 'is_alive']
@staticmethod
def get_proxy_online(obj):
......@@ -31,6 +32,7 @@ class TerminalSerializer(serializers.ModelSerializer):
class TerminalHeatbeatSerializer(serializers.ModelSerializer):
date_start = serializers.DateTimeField
class Meta:
model = TerminalHeatbeat
......
......@@ -99,6 +99,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
return fields
class AssetSystemUserSerializer(serializers.ModelSerializer):
class Meta:
model = SystemUser
fields = ('id', 'name', 'username', 'protocol', 'auth_method', 'comment')
class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
......@@ -145,13 +151,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class AssetGrantedSerializer(serializers.ModelSerializer):
system_users = SystemUserSerializer(many=True, read_only=True)
system_users_granted = AssetSystemUserSerializer(many=True, read_only=True)
is_inherited = serializers.SerializerMethodField()
system_users_join = serializers.SerializerMethodField()
class Meta(object):
model = Asset
fields = ("id", "hostname", "ip", "port", "system_users", "is_inherited",
fields = ("id", "hostname", "ip", "port", "system_users_granted", "is_inherited",
"is_active", "system_users_join", "comment")
@staticmethod
......@@ -163,7 +169,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
@staticmethod
def get_system_users_join(obj):
return ', '.join([system_user.username for system_user in obj.system_users.all()])
return ', '.join([system_user.username for system_user in obj.system_users_granted])
class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer):
......
......@@ -17,10 +17,13 @@ class LoginLog(models.Model):
username = models.CharField(max_length=20, verbose_name=_('Username'))
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name'))
login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, verbose_name=_('Login type'))
login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2,
verbose_name=_('Login type'))
login_ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
login_city = models.CharField(max_length=100, blank=True, null=True, verbose_name=_('Login city'))
user_agent = models.CharField(max_length=100, blank=True, null=True, verbose_name=_('User agent'))
login_city = models.CharField(max_length=100, blank=True, null=True,
verbose_name=_('Login city'))
user_agent = models.CharField(max_length=100, blank=True, null=True,
verbose_name=_('User agent'))
date_login = models.DateTimeField(auto_now_add=True, verbose_name=_('Date login'))
class Meta:
......@@ -66,7 +69,8 @@ class ProxyLog(models.Model):
class CommandLog(models.Model):
proxy_log = models.ForeignKey(ProxyLog, on_delete=models.CASCADE, related_name='commands')
proxy_log = models.ForeignKey(ProxyLog, on_delete=models.CASCADE,
related_name='commands')
command_no = models.IntegerField()
command = models.CharField(max_length=1000, blank=True)
output = models.TextField(blank=True)
......@@ -78,7 +82,8 @@ class CommandLog(models.Model):
@property
def output_decode(self):
try:
return base64.b64decode(self.output).replace('\n', '<br />')
return base64.b64decode(self.output).decode('utf-8') \
.replace('\n', '<br />')
except UnicodeDecodeError:
return 'UnicodeDecodeError'
......
......@@ -13,8 +13,9 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class Meta:
model = models.ProxyLog
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user', 'login_type', 'terminal',
'log_file', 'was_failed', 'is_finished', 'date_start', 'date_finished', 'time',
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user',
'login_type', 'terminal', 'log_file', 'was_failed',
'is_finished', 'date_start', 'date_finished', 'time',
'command_length', "commands_dict"]
@staticmethod
......@@ -32,3 +33,4 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class CommandLogSerializer(serializers.ModelSerializer):
class Meta:
model = models.CommandLog
fields = '__all__'
......@@ -83,7 +83,7 @@
<td>{{ command.proxy_log.system_user }}</td>
<td><a href="{% url 'audits:proxy-log-detail' pk=command.proxy_log.id %}">{{ command.proxy_log.id}}</a></td>
<td>{{ command.datetime }}</td>
<td>{{ command.output_decode |safe }}</td>
<td>{{ command.output_decode|safe }}</td>
</tr>
{% endfor %}
</tbody>
......
......@@ -52,7 +52,7 @@
<tr>
<td>{{ command.command_no }}</td>
<td>{{ command.command }}</td>
<td>{{ command.output_decode |safe }}</td>
<td>{{ command.output_decode|safe }}</td>
<td>{{ command.datetime }}</td>
</tr>
{% endfor %}
......@@ -68,30 +68,6 @@
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Detail' %} <b>{{ user_object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table2 table-stripped toggle-arrow-tiny" data-page-size="8">
</table>
</div>
</div>
</div>
</div>
</div>
</div>
......
......@@ -14,17 +14,16 @@ from .models import ProxyLog, CommandLog, LoginLog
from .hands import User, Asset, SystemUser, AdminUserRequiredMixin
date_now = timezone.localtime(timezone.now())
now_s = date_now.strftime('%m/%d/%Y')
seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
class ProxyLogListView(AdminUserRequiredMixin, ListView):
model = ProxyLog
template_name = 'audits/proxy_log_list.html'
context_object_name = 'proxy_log_list'
def get_queryset(self):
date_now = timezone.localtime(timezone.now())
now_s = date_now.strftime('%m/%d/%Y')
seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
self.queryset = super(ProxyLogListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.username = username = self.request.GET.get('username', '')
......@@ -37,7 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
self.queryset = self.queryset.filter(date_start__gt=date_from)
if date_to_s:
date_to = timezone.datetime.strptime(date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
date_to = timezone.datetime.strptime(date_to_s + ' 23:59:59',
'%m/%d/%Y %H:%M:%S')
self.queryset = self.queryset.filter(date_start__lt=date_to)
if username:
self.queryset = self.queryset.filter(username=username)
......@@ -54,7 +54,6 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return self.queryset
def get_context_data(self, **kwargs):
print(self.date_to_s)
context = {
'app': _('Audits'),
'action': _('Proxy log list'),
......@@ -110,6 +109,9 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
context_object_name = 'command_list'
def get_queryset(self):
date_now = timezone.localtime(timezone.now())
now_s = date_now.strftime('%m/%d/%Y')
seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
self.queryset = super(CommandLogListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-datetime')
......@@ -161,6 +163,9 @@ class LoginLogListView(AdminUserRequiredMixin, ListView):
context_object_name = 'login_log_list'
def get_queryset(self):
date_now = timezone.localtime(timezone.now())
now_s = date_now.strftime('%m/%d/%Y')
seven_days_ago_s = (date_now - timezone.timedelta(7)).strftime('%m/%d/%Y')
self.queryset = super(LoginLogListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.username = username = self.request.GET.get('username', '')
......
......@@ -16,5 +16,6 @@ app = Celery('jumpserver')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS])
app.autodiscover_tasks(lambda: [app_config.split('.')[0]
for app_config in settings.INSTALLED_APPS])
# ~*~ coding: utf-8 ~*~
#
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response
from rest_framework.decorators import api_view
from rest_framework.generics import ListAPIView, get_object_or_404
from rest_framework import viewsets
from users.permissions import IsValidUser, IsSuperUser
from users.permissions import IsValidUser, IsSuperUser, IsAppUser
from common.utils import get_object_or_none
from .utils import get_user_granted_assets, get_user_granted_asset_groups, get_user_asset_permissions, \
get_user_group_asset_permissions, get_user_group_granted_assets, get_user_group_granted_asset_groups
from .utils import get_user_granted_assets, get_user_granted_asset_groups, \
get_user_asset_permissions, get_user_group_asset_permissions, \
get_user_group_granted_assets, get_user_group_granted_asset_groups
from .models import AssetPermission
from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, AssetGroup, AssetGroupSerializer
from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, \
AssetGroup, AssetGroupSerializer, SystemUser
from . import serializers
......@@ -80,11 +83,12 @@ class UserGrantedAssetsApi(ListAPIView):
def get_queryset(self):
user_id = self.kwargs.get('pk', '')
queryset = []
if user_id:
user = get_object_or_404(User, id=user_id)
queryset = get_user_granted_assets(user)
else:
queryset = []
for k, v in get_user_granted_assets(user).items():
k.system_users_granted = v
queryset.append(k)
return queryset
......@@ -104,19 +108,26 @@ class UserGrantedAssetGroupsApi(ListAPIView):
class MyGrantedAssetsApi(ListAPIView):
"""授权给用户的资产列表
[{'hostname': 'x','ip': 'x', ..,
'system_users_granted': [{'name': 'x', .}, ...]
"""
permission_classes = (IsValidUser,)
serializer_class = AssetGrantedSerializer
def get_queryset(self):
queryset = []
user = self.request.user
if user:
queryset = get_user_granted_assets(user)
else:
queryset = []
for asset, system_users in get_user_granted_assets(user).items():
asset.system_users_granted = system_users
queryset.append(asset)
return queryset
class MyGrantedAssetsGroupsApi(APIView):
"""授权给用户的资产组列表, 非直接通过授权规则授权的资产组列表, 而是授权资产的所有
资产组之和"""
permission_classes = (IsValidUser,)
def get(self, request, *args, **kwargs):
......@@ -141,6 +152,7 @@ class MyGrantedAssetsGroupsApi(APIView):
class MyAssetGroupAssetsApi(ListAPIView):
"""授权用户资产组下的资产列表, 非该资产组的所有资产,而是被授权的"""
permission_classes = (IsValidUser,)
serializer_class = AssetGrantedSerializer
......@@ -152,8 +164,9 @@ class MyAssetGroupAssetsApi(ListAPIView):
if user and asset_group:
assets = get_user_granted_assets(user)
for asset in assets:
if asset_group in asset.groups.all():
for asset in asset_group.assets.all():
if asset in assets:
asset.system_users_granted = assets[asset]
queryset.append(asset)
return queryset
......@@ -185,4 +198,24 @@ class UserGroupGrantedAssetGroupsApi(ListAPIView):
queryset = get_user_group_granted_asset_groups(user_group)
else:
queryset = []
return queryset
\ No newline at end of file
return queryset
class CheckUserAssetSystemPermission(APIView):
permission_classes = (IsAppUser,)
def get(self, request):
user_id = request.params.get('user_id', '')
asset_id = request.params.get('asset_id', '')
system_id = request.params.get('system_id', '')
user = get_object_or_none(User, id=user_id)
asset = get_object_or_none(Asset, id=asset_id)
system_user = get_object_or_none(SystemUser, id=system_id)
if not (user and asset and system_user):
return Response(status=403)
assets_granted = get_user_granted_assets(user)
......@@ -37,6 +37,8 @@ def get_user_group_granted_assets(user_group):
if not asset_permission.is_valid:
continue
for asset in asset_permission.get_granted_assets():
if not asset.is_active:
continue
if asset in assets:
assets[asset] |= set(asset_permission.system_users.all())
else:
......@@ -127,6 +129,8 @@ def get_user_granted_assets_direct(user):
if not asset_permission.is_valid:
continue
for asset in asset_permission.get_granted_assets():
if not asset.is_active:
continue
if asset in assets:
assets[asset] |= set(asset_permission.system_users.all())
else:
......@@ -147,12 +151,13 @@ def get_user_granted_assets_inherit_from_user_groups(user):
for user_group in user_groups:
assets_inherited = get_user_group_granted_assets(user_group)
for asset in assets_inherited:
if not asset.is_active:
continue
if asset in assets:
assets[asset] |= assets_inherited[asset]
else:
setattr(asset, 'inherited', True)
assets[asset] = assets_inherited[asset]
return assets
......@@ -167,6 +172,8 @@ def get_user_granted_assets(user):
assets = assets_inherited
for asset in assets_direct:
if not asset.is_active:
continue
if asset in assets:
assets[asset] |= assets_direct[asset]
else:
......
......@@ -3,23 +3,22 @@
import base64
from django.core.cache import cache
from django.conf import settings
from rest_framework import generics, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework.permissions import AllowAny
from rest_framework.authentication import SessionAuthentication
from rest_framework_bulk import BulkModelViewSet
from rest_framework.authentication import CSRFCheck
# from django_filters.rest_framework import DjangoFilterBackend
from django.conf import settings
from common.mixins import IDInFilterMixin
from common.utils import get_logger
from .utils import check_user_valid, generate_token
from .models import User, UserGroup
from .hands import write_login_log_async
from .permissions import IsSuperUser, IsAppUser, IsValidUser, IsSuperUserOrAppUser
from .permissions import (
IsSuperUser, IsAppUser, IsValidUser, IsSuperUserOrAppUser)
from . import serializers
......@@ -98,8 +97,9 @@ class UserToken(APIView):
password = request.data.get('password', '')
public_key = request.data.get('public_key', '')
user, msg = check_user_valid(username=username, email=email,
password=password, public_key=public_key)
user, msg = check_user_valid(
username=username, email=email,
password=password, public_key=public_key)
else:
user = request.user
msg = None
......@@ -116,24 +116,29 @@ class UserProfile(APIView):
def get(self, request):
return Response(request.user.to_json())
def post(self, request):
return Response(request.user.to_json())
class UserAuthApi(APIView):
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
def post(self, request):
username = request.data.get('username', '')
password = request.data.get('password', '')
public_key = request.data.get('public_key', '')
login_type = request.data.get('login_type', '')
login_ip = request.data.get('remote_addr', None) or request.META.get('REMOTE_ADDR', '')
login_ip = request.data.get('remote_addr', None)
user_agent = request.data.get('HTTP_USER_AGENT', '')
user, msg = check_user_valid(username=username, password=password, public_key=public_key)
user, msg = check_user_valid(username=username, password=password,
public_key=public_key)
if user:
token = generate_token(request, user)
write_login_log_async.delay(user.username, name=user.name, user_agent=user_agent,
login_ip=login_ip, login_type=login_type)
write_login_log_async.delay(user.username, name=user.name,
user_agent=user_agent, login_ip=login_ip,
login_type=login_type)
return Response({'token': token, 'user': user.to_json()})
else:
return Response({'msg': msg}, status=401)
......@@ -8,10 +8,11 @@ import time
from django.core.cache import cache
from django.conf import settings
from django.utils.translation import ugettext as _
from rest_framework import authentication, exceptions, permissions
from django.utils.six import text_type
from django.utils.translation import ugettext_lazy as _
from rest_framework import HTTP_HEADER_ENCODING
from rest_framework import authentication, exceptions, permissions
from rest_framework.authentication import CSRFCheck
from common.utils import get_object_or_none, make_signature, http_to_unixtime
from .utils import refresh_token
......@@ -27,6 +28,21 @@ def get_request_date_header(request):
class AccessKeyAuthentication(authentication.BaseAuthentication):
"""App使用Access key进行签名认证, 目前签名算法比较简单,
app注册或者手动建立后,会生成 access_key_id 和 access_key_secret,
然后使用 如下算法生成签名:
Signature = md5(access_key_secret + '\n' + Date)
example: Signature = md5('d32d2b8b-9a10-4b8d-85bb-1a66976f6fdc' + '\n' +
'Thu, 12 Jan 2017 08:19:41 GMT')
请求时设置请求header
header['Authorization'] = 'Sign access_key_id:Signature' 如:
header['Authorization'] =
'Sign d32d2b8b-9a10-4b8d-85bb-1a66976f6fdc:OKOlmdxgYPZ9+SddnUUDbQ=='
验证时根据相同算法进行验证, 取到access_key_id对应的access_key_id, 从request
headers取到Date, 然后进行md5, 判断得到的结果是否相同, 如果是认证通过, 否则 认证
失败
"""
keyword = 'Sign'
model = AccessKey
......@@ -40,22 +56,26 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
msg = _('Invalid signature header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid signature header. Signature string should not contain spaces.')
msg = _('Invalid signature header. Signature '
'string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
sign = auth[1].decode().split(':')
if len(sign) != 2:
msg = _('Invalid signature header. Format like AccessKeyId:Signature')
msg = _('Invalid signature header. '
'Format like AccessKeyId:Signature')
raise exceptions.AuthenticationFailed(msg)
except UnicodeError:
msg = _('Invalid signature header. Signature string should not contain invalid characters.')
msg = _('Invalid signature header. '
'Signature string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
access_key_id = sign[0]
request_signature = sign[1]
return self.authenticate_credentials(request, access_key_id, request_signature)
return self.authenticate_credentials(
request, access_key_id, request_signature)
@staticmethod
def authenticate_credentials(request, access_key_id, request_signature):
......@@ -68,14 +88,17 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
try:
request_unix_time = http_to_unixtime(request_date)
except ValueError:
raise exceptions.AuthenticationFailed(_('HTTP header: Date not provide or not %a, %d %b %Y %H:%M:%S GMT'))
raise exceptions.AuthenticationFailed(
_('HTTP header: Date not provide '
'or not %a, %d %b %Y %H:%M:%S GMT'))
if int(time.time()) - request_unix_time > 15*60:
raise exceptions.AuthenticationFailed(_('Expired, more than 15 minutes'))
if int(time.time()) - request_unix_time > 15 * 60:
raise exceptions.AuthenticationFailed(
_('Expired, more than 15 minutes'))
signature = make_signature(access_key_secret, request_date)
if not signature == request_signature:
raise exceptions.AuthenticationFailed(_('Invalid signature. %s: %s' % (signature, request_signature)))
raise exceptions.AuthenticationFailed(_('Invalid signature.'))
if not access_key.user.is_active:
raise exceptions.AuthenticationFailed(_('User disabled.'))
......@@ -97,13 +120,15 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Sign string should not contain spaces.')
msg = _('Invalid token header. Sign string '
'should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Sign string should not contain invalid characters.')
msg = _('Invalid token header. Sign string '
'should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
......@@ -125,4 +150,6 @@ class PrivateTokenAuthentication(authentication.TokenAuthentication):
class SessionAuthentication(authentication.SessionAuthentication):
def enforce_csrf(self, request):
return None
\ No newline at end of file
reason = CSRFCheck().process_view(request, None, (), {})
if reason:
raise exceptions.AuthenticationFailed(reason)
......@@ -16,7 +16,8 @@ class AccessKey(models.Model):
default=uuid.uuid4, editable=False)
secret = models.UUIDField(verbose_name='AccessKeySecret',
default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, verbose_name='User', related_name='access_key')
user = models.ForeignKey(User, verbose_name='User',
related_name='access_key')
def get_id(self):
return str(self.id)
......
......@@ -18,9 +18,12 @@ urlpatterns = [
url(r'^v1/token/$', api.UserToken.as_view(), name='user-token'),
url(r'^v1/profile/$', api.UserProfile.as_view(), name='user-profile'),
url(r'^v1/auth/$', api.UserAuthApi.as_view(), name='user-auth'),
url(r'^v1/users/(?P<pk>\d+)/password/reset/$', api.UserResetPasswordApi.as_view(), name='user-reset-password'),
url(r'^v1/users/(?P<pk>\d+)/public-key/reset/$', api.UserResetPKApi.as_view(), name='user-public-key-reset'),
url(r'^v1/users/(?P<pk>\d+)/public-key/update/$', api.UserUpdatePKApi.as_view(), name='user-public-key-update'),
url(r'^v1/users/(?P<pk>\d+)/password/reset/$',
api.UserResetPasswordApi.as_view(), name='user-reset-password'),
url(r'^v1/users/(?P<pk>\d+)/public-key/reset/$',
api.UserResetPKApi.as_view(), name='user-public-key-reset'),
url(r'^v1/users/(?P<pk>\d+)/public-key/update/$',
api.UserUpdatePKApi.as_view(), name='user-public-key-update'),
url(r'^v1/users/(?P<pk>\d+)/groups/$',
api.UserUpdateGroupApi.as_view(), name='user-update-group'),
url(r'^v1/user-groups/(?P<pk>\d+)/users/$',
......
......@@ -6,39 +6,72 @@ from .. import views
app_name = 'users'
urlpatterns = [
# Login view
url(r'^login$', views.UserLoginView.as_view(), name='login'),
url(r'^logout$', views.UserLogoutView.as_view(), name='logout'),
url(r'^password/forgot$', views.UserForgotPasswordView.as_view(), name='forgot-password'),
url(r'^password/forgot$', views.UserForgotPasswordView.as_view(),
name='forgot-password'),
url(r'^password/forgot/sendmail-success$',
views.UserForgotPasswordSendmailSuccessView.as_view(), name='forgot-password-sendmail-success'),
url(r'^password/reset$', views.UserResetPasswordView.as_view(), name='reset-password'),
url(r'^password/reset/success$', views.UserResetPasswordSuccessView.as_view(),
views.UserForgotPasswordSendmailSuccessView.as_view(),
name='forgot-password-sendmail-success'),
url(r'^password/reset$', views.UserResetPasswordView.as_view(),
name='reset-password'),
url(r'^password/reset/success$',
views.UserResetPasswordSuccessView.as_view(),
name='reset-password-success'),
# User view
url(r'^user$', views.UserListView.as_view(), name='user-list'),
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/(?P<pk>[0-9]+)/asset-permission$', views.UserAssetPermissionView.as_view(),
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(),
name='user-detail'),
url(r'^user/(?P<pk>[0-9]+)/asset-permission$',
views.UserAssetPermissionView.as_view(),
name='user-asset-permission'),
url(r'^user/(?P<pk>[0-9]+)/asset-permission/create$', views.UserAssetPermissionCreateView.as_view(),
url(r'^user/(?P<pk>[0-9]+)/asset-permission/create$',
views.UserAssetPermissionCreateView.as_view(),
name='user-asset-permission-create'),
url(r'^user/(?P<pk>[0-9]+)/assets', views.UserGrantedAssetView.as_view(), name='user-granted-asset'),
url(r'^user/(?P<pk>[0-9]+)/login-history', views.UserDetailView.as_view(), name='user-login-history'),
url(r'^user/export/', views.UserExportView.as_view(), name='user-export'),
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
url(r'^user/import/$', views.BulkImportUserView.as_view(), name='user-import'),
# url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
url(r'^user/(?P<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),
url(r'^user/(?P<pk>[0-9]+)/assets',
views.UserGrantedAssetView.as_view(),
name='user-granted-asset'),
url(r'^user/(?P<pk>[0-9]+)/login-history',
views.UserDetailView.as_view(),
name='user-login-history'),
url(r'^user/export/',
views.UserExportView.as_view(),
name='user-export'),
url(r'^first-login/$',
views.UserFirstLoginView.as_view(),
name='user-first-login'),
url(r'^user/import/$',
views.UserBulkImportView.as_view(),
name='user-import'),
url(r'^user/create$',
views.UserCreateView.as_view(),
name='user-create'),
url(r'^user/(?P<pk>[0-9]+)/update$',
views.UserUpdateView.as_view(),
name='user-update'),
# User group view
url(r'^user-group$', views.UserGroupListView.as_view(), name='user-group-list'),
url(r'^user-group/(?P<pk>[0-9]+)$', views.UserGroupDetailView.as_view(), name='user-group-detail'),
url(r'^user-group/create$', views.UserGroupCreateView.as_view(), name='user-group-create'),
url(r'^user-group/(?P<pk>[0-9]+)/update$', views.UserGroupUpdateView.as_view(), name='user-group-update'),
url(r'^user-group/(?P<pk>[0-9]+)/asset-permission$', views.UserGroupAssetPermissionView.as_view(),
url(r'^user-group$',
views.UserGroupListView.as_view(),
name='user-group-list'),
url(r'^user-group/(?P<pk>[0-9]+)$',
views.UserGroupDetailView.as_view(),
name='user-group-detail'),
url(r'^user-group/create$',
views.UserGroupCreateView.as_view(),
name='user-group-create'),
url(r'^user-group/(?P<pk>[0-9]+)/update$',
views.UserGroupUpdateView.as_view(),
name='user-group-update'),
url(r'^user-group/(?P<pk>[0-9]+)/asset-permission$',
views.UserGroupAssetPermissionView.as_view(),
name='user-group-asset-permission'),
url(r'^user-group/(?P<pk>[0-9]+)/asset-permission/create$', views.UserGroupAssetPermissionCreateView.as_view(),
url(r'^user-group/(?P<pk>[0-9]+)/asset-permission/create$',
views.UserGroupAssetPermissionCreateView.as_view(),
name='user-group-asset-permission-create'),
url(r'^user-group/(?P<pk>[0-9]+)/assets', views.UserGroupGrantedAssetView.as_view(),
url(r'^user-group/(?P<pk>[0-9]+)/assets',
views.UserGroupGrantedAssetView.as_view(),
name='user-group-granted-asset'),
]
# ~*~ coding: utf-8 ~*~
from .login import *
from .user import *
from .group import *
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from django import forms
from django.shortcuts import reverse, redirect
from django.utils.translation import ugettext as _
from django.urls import reverse_lazy
from django.views.generic import ListView
from django.views.generic.base import TemplateView
from django.views.generic.edit import CreateView, UpdateView, FormMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from common.utils import get_logger
from perms.models import AssetPermission
from ..models import User, UserGroup
from ..utils import AdminUserRequiredMixin
from .. import forms
__all__ = ['UserGroupListView', 'UserGroupCreateView', 'UserGroupDetailView',
'UserGroupUpdateView', 'UserGroupAssetPermissionCreateView',
'UserGroupAssetPermissionView', 'UserGroupGrantedAssetView']
logger = get_logger(__name__)
class UserGroupListView(AdminUserRequiredMixin, TemplateView):
template_name = 'users/user_group_list.html'
def get_context_data(self, **kwargs):
context = super(UserGroupListView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('User group list')})
return context
class UserGroupCreateView(AdminUserRequiredMixin, CreateView):
model = UserGroup
form_class = forms.UserGroupForm
template_name = 'users/user_group_create_update.html'
success_url = reverse_lazy('users:user-group-list')
def get_context_data(self, **kwargs):
context = super(UserGroupCreateView, self).get_context_data(**kwargs)
users = User.objects.all()
context.update({'app': _('Users'), 'action': _('Create user group'),
'users': users})
return context
def form_valid(self, form):
user_group = form.save()
users_id_list = self.request.POST.getlist('users', [])
users = User.objects.filter(id__in=users_id_list)
user_group.created_by = self.request.user.username or 'Admin'
user_group.users.add(*users)
user_group.save()
return super(UserGroupCreateView, self).form_valid(form)
class UserGroupUpdateView(AdminUserRequiredMixin, UpdateView):
model = UserGroup
form_class = forms.UserGroupForm
template_name = 'users/user_group_create_update.html'
success_url = reverse_lazy('users:user-group-list')
def get_context_data(self, **kwargs):
# self.object = self.get_object()
context = super(UserGroupUpdateView, self).get_context_data(**kwargs)
users = User.objects.all()
group_users = [user.id for user in self.object.users.all()]
context.update({
'app': _('Users'),
'action': _('Update User Group'),
'users': users,
'group_users': group_users
})
return context
def form_valid(self, form):
user_group = form.save()
users_id_list = self.request.POST.getlist('users', [])
users = User.objects.filter(id__in=users_id_list)
user_group.users.clear()
user_group.users.add(*users)
user_group.save()
return super(UserGroupUpdateView, self).form_valid(form)
class UserGroupDetailView(AdminUserRequiredMixin, DetailView):
model = UserGroup
context_object_name = 'user_group'
template_name = 'users/user_group_detail.html'
def get_context_data(self, **kwargs):
users = User.objects.exclude(id__in=self.object.users.all())
context = {
'app': _('Users'),
'action': _('User Group Detail'),
'users': users,
}
kwargs.update(context)
return super(UserGroupDetailView, self).get_context_data(**kwargs)
class UserGroupAssetPermissionView(AdminUserRequiredMixin, FormMixin,
SingleObjectMixin, ListView):
model = UserGroup
template_name = 'users/user_group_asset_permission.html'
context_object_name = 'user_group'
form_class = forms.UserPrivateAssetPermissionForm
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=UserGroup.objects.all())
return super(UserGroupAssetPermissionView, self)\
.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = {
'app': 'Users',
'action': 'User group asset permissions',
}
kwargs.update(context)
return super(UserGroupAssetPermissionView, self)\
.get_context_data(**kwargs)
class UserGroupAssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
form_class = forms.UserGroupPrivateAssetPermissionForm
model = AssetPermission
def get(self, request, *args, **kwargs):
user_group = self.get_object(queryset=UserGroup.objects.all())
return redirect(reverse('users:user-group-asset-permission',
kwargs={'pk': user_group.id}))
def post(self, request, *args, **kwargs):
self.user_group = self.get_object(queryset=UserGroup.objects.all())
return super(UserGroupAssetPermissionCreateView, self)\
.post(request, *args, **kwargs)
def get_form(self, form_class=None):
form = super(UserGroupAssetPermissionCreateView, self)\
.get_form(form_class=form_class)
form.user_group = self.user_group
return form
def form_invalid(self, form):
return redirect(reverse('users:user-group-asset-permission',
kwargs={'pk': self.user_group.id}))
def get_success_url(self):
return reverse('users:user-group-asset-permission',
kwargs={'pk': self.user_group.id})
class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView):
model = User
template_name = 'users/user_group_granted_asset.html'
context_object_name = 'user_group'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=UserGroup.objects.all())
return super(UserGroupGrantedAssetView, self)\
.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = {
'app': 'User',
'action': 'User group granted asset',
}
kwargs.update(context)
return super(UserGroupGrantedAssetView, self).get_context_data(**kwargs)
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from django import forms
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.files.storage import default_storage
from django.http import HttpResponseRedirect
from django.shortcuts import reverse, redirect
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from formtools.wizard.views import SessionWizardView
from common.utils import get_object_or_none
from ..models import User
from ..utils import send_reset_password_mail
from ..hands import write_login_log_async
from .. import forms
__all__ = ['UserLoginView', 'UserLogoutView',
'UserForgotPasswordView', 'UserForgotPasswordSendmailSuccessView',
'UserResetPasswordView', 'UserResetPasswordSuccessView',
'UserFirstLoginView']
@method_decorator(sensitive_post_parameters(), name='dispatch')
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(never_cache, name='dispatch')
class UserLoginView(FormView):
template_name = 'users/login.html'
form_class = forms.UserLoginForm
redirect_field_name = 'next'
def get(self, request, *args, **kwargs):
if request.user.is_staff:
return redirect(self.get_success_url())
return super(UserLoginView, self).get(request, *args, **kwargs)
def form_valid(self, form):
auth_login(self.request, form.get_user())
login_ip = self.request.META.get('REMOTE_ADDR', '')
user_agent = self.request.META.get('HTTP_USER_AGENT', '')
write_login_log_async.delay(self.request.user.username,
self.request.user.name,
login_type='W', login_ip=login_ip,
user_agent=user_agent)
return redirect(self.get_success_url())
def get_success_url(self):
if self.request.user.is_first_login:
return reverse('users:user-first-login')
return self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, reverse('index')))
@method_decorator(never_cache, name='dispatch')
class UserLogoutView(TemplateView):
template_name = 'flash_message_standalone.html'
def get(self, request, *args, **kwargs):
auth_logout(request)
return super(UserLogoutView, self).get(request)
def get_context_data(self, **kwargs):
context = {
'title': _('Logout success'),
'messages': _('Logout success, return login page'),
'redirect_url': reverse('users:login'),
'auto_redirect': True,
}
kwargs.update(context)
return super(UserLogoutView, self).get_context_data(**kwargs)
class UserForgotPasswordView(TemplateView):
template_name = 'users/forgot_password.html'
def post(self, request):
email = request.POST.get('email')
user = get_object_or_none(User, email=email)
if not user:
return self.get(request, errors=_('Email address invalid, input again'))
else:
send_reset_password_mail(user)
return HttpResponseRedirect(
reverse('users:forgot-password-sendmail-success'))
class UserForgotPasswordSendmailSuccessView(TemplateView):
template_name = 'flash_message_standalone.html'
def get_context_data(self, **kwargs):
context = {
'title': _('Send reset password message'),
'messages': _('Send reset password mail success, '
'login your mail box and follow it '),
'redirect_url': reverse('users:login'),
}
kwargs.update(context)
return super(UserForgotPasswordSendmailSuccessView, self)\
.get_context_data(**kwargs)
class UserResetPasswordSuccessView(TemplateView):
template_name = 'flash_message_standalone.html'
def get_context_data(self, **kwargs):
context = {
'title': _('Reset password success'),
'messages': _('Reset password success, return to login page'),
'redirect_url': reverse('users:login'),
'auto_redirect': True,
}
kwargs.update(context)
return super(UserResetPasswordSuccessView, self).get_context_data(**kwargs)
class UserResetPasswordView(TemplateView):
template_name = 'users/reset_password.html'
def get(self, request, *args, **kwargs):
token = request.GET.get('token')
user = User.validate_reset_token(token)
if not user:
kwargs.update({'errors': _('Token invalid or expired')})
return super(UserResetPasswordView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
password = request.POST.get('password')
password_confirm = request.POST.get('password-confirm')
token = request.GET.get('token')
if password != password_confirm:
return self.get(request, errors=_('Password not same'))
user = User.validate_reset_token(token)
if not user:
return self.get(request, errors=_('Token invalid or expired'))
user.reset_password(password)
return HttpResponseRedirect(reverse('users:reset-password-success'))
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
template_name = 'users/first_login.html'
form_list = [forms.UserInfoForm, forms.UserKeyForm]
file_storage = default_storage
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and not request.user.is_first_login:
return redirect(reverse('index'))
return super(UserFirstLoginView, self).dispatch(request, *args, **kwargs)
def done(self, form_list, form_dict, **kwargs):
user = self.request.user
for form in form_list:
for field in form:
if field.value():
setattr(user, field.name, field.value())
if field.name == 'enable_otp':
user.enable_otp = field.value()
user.is_first_login = False
user.is_public_key_valid = True
user.save()
return redirect(reverse('index'))
def get_context_data(self, **kwargs):
context = super(UserFirstLoginView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('First Login')})
return context
def get_form_initial(self, step):
user = self.request.user
if step == '0':
return {
'name': user.name or user.username,
'enable_otp': user.enable_otp or True,
'wechat': user.wechat or '',
'phone': user.phone or ''
}
return super(UserFirstLoginView, self).get_form_initial(step)
def get_form(self, step=None, data=None, files=None):
form = super(UserFirstLoginView, self).get_form(step, data, files)
if step is None:
step = self.steps.current
if step == '1':
form.user = self.request.user
return form
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