mirror of https://github.com/jumpserver/jumpserver
[Update] 修改注册流程
parent
8b081cd6b0
commit
f4beccddae
|
@ -0,0 +1 @@
|
||||||
|
.git
|
|
@ -258,7 +258,8 @@ LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'), ]
|
||||||
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
STATIC_ROOT = os.path.join(PROJECT_DIR, "data", "static")
|
||||||
|
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
||||||
|
|
||||||
|
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (
|
||||||
|
|
|
@ -36,6 +36,6 @@ urlpatterns = [
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
url(r'^docs/', schema_view, name="docs"),
|
url(r'^docs/', schema_view, name="docs"),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_DIR) \
|
||||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
|
|
||||||
from rest_framework import viewsets, serializers
|
from rest_framework import viewsets, serializers
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
|
from django.core.cache import cache
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
|
@ -35,7 +37,7 @@ class TerminalViewSet(viewsets.ModelViewSet):
|
||||||
x_real_ip = request.META.get('X-Real-IP')
|
x_real_ip = request.META.get('X-Real-IP')
|
||||||
remote_addr = x_real_ip or remote_ip
|
remote_addr = x_real_ip or remote_ip
|
||||||
|
|
||||||
terminal = get_object_or_none(Terminal, name=name)
|
terminal = get_object_or_none(Terminal, name=name, is_deleted=False)
|
||||||
if terminal:
|
if terminal:
|
||||||
msg = 'Terminal name %s already used' % name
|
msg = 'Terminal name %s already used' % name
|
||||||
return Response({'msg': msg}, status=409)
|
return Response({'msg': msg}, status=409)
|
||||||
|
@ -46,12 +48,11 @@ class TerminalViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
terminal = serializer.save()
|
terminal = serializer.save()
|
||||||
app_user, access_key = terminal.create_app_user()
|
|
||||||
data = OrderedDict()
|
# App should use id, token get access key, if accepted
|
||||||
data['terminal'] = copy.deepcopy(serializer.data)
|
token = uuid.uuid4().hex
|
||||||
data['user'] = app_user.to_json()
|
cache.set(token, str(terminal.id), 3600)
|
||||||
data['access_key'] = {'id': access_key.id,
|
data = {"id": str(terminal.id), "token": token, "msg": "Need accept"}
|
||||||
'secret': access_key.secret}
|
|
||||||
return Response(data, status=201)
|
return Response(data, status=201)
|
||||||
else:
|
else:
|
||||||
data = serializer.errors
|
data = serializer.errors
|
||||||
|
@ -63,6 +64,36 @@ class TerminalViewSet(viewsets.ModelViewSet):
|
||||||
return super().get_permissions()
|
return super().get_permissions()
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalTokenApi(APIView):
|
||||||
|
permission_classes = (AllowAny,)
|
||||||
|
queryset = Terminal.objects.filter(is_deleted=False)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
terminal = self.queryset.get(id=kwargs.get('terminal'))
|
||||||
|
except Terminal.DoesNotExist:
|
||||||
|
terminal = None
|
||||||
|
|
||||||
|
token = request.query_params.get("token")
|
||||||
|
|
||||||
|
if terminal is None:
|
||||||
|
return Response('May be reject by administrator', status=401)
|
||||||
|
|
||||||
|
if token is None or cache.get(token, "") != str(terminal.id):
|
||||||
|
return Response('Token is not valid', status=401)
|
||||||
|
|
||||||
|
if not terminal.is_accepted:
|
||||||
|
return Response("Terminal was not accepted yet", status=400)
|
||||||
|
|
||||||
|
if not terminal.user or not terminal.user.access_key.all():
|
||||||
|
return Response("No access key generate", status=401)
|
||||||
|
|
||||||
|
access_key = terminal.user.access_key.first()
|
||||||
|
data = OrderedDict()
|
||||||
|
data['access_key'] = {'id': access_key.id, 'secret': access_key.secret}
|
||||||
|
return Response(data, status=200)
|
||||||
|
|
||||||
|
|
||||||
class StatusViewSet(viewsets.ModelViewSet):
|
class StatusViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Status.objects.all()
|
queryset = Status.objects.all()
|
||||||
serializer_class = StatusSerializer
|
serializer_class = StatusSerializer
|
||||||
|
|
|
@ -11,7 +11,7 @@ from .backends.command.models import AbstractSessionCommand
|
||||||
|
|
||||||
class Terminal(models.Model):
|
class Terminal(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=32, unique=True, verbose_name=_('Name'))
|
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||||
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
|
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
|
||||||
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
||||||
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
||||||
|
@ -34,7 +34,8 @@ class Terminal(models.Model):
|
||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
||||||
def create_app_user(self):
|
def create_app_user(self):
|
||||||
user, access_key = User.create_app_user(name=self.name, comment=self.comment)
|
random = uuid.uuid4().hex[:6]
|
||||||
|
user, access_key = User.create_app_user(name="{}-{}".format(self.name, random), comment=self.comment)
|
||||||
self.user = user
|
self.user = user
|
||||||
self.save()
|
self.save()
|
||||||
return user, access_key
|
return user, access_key
|
||||||
|
@ -42,6 +43,7 @@ class Terminal(models.Model):
|
||||||
def delete(self, using=None, keep_parents=False):
|
def delete(self, using=None, keep_parents=False):
|
||||||
if self.user:
|
if self.user:
|
||||||
self.user.delete()
|
self.user.delete()
|
||||||
|
self.user = None
|
||||||
self.is_deleted = True
|
self.is_deleted = True
|
||||||
self.save()
|
self.save()
|
||||||
return
|
return
|
||||||
|
|
|
@ -14,8 +14,11 @@ class TerminalSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Terminal
|
model = Terminal
|
||||||
fields = ['id', 'name', 'remote_addr', 'http_port', 'ssh_port',
|
fields = [
|
||||||
'comment', 'is_accepted', 'session_online', 'is_alive']
|
'id', 'name', 'remote_addr', 'http_port', 'ssh_port',
|
||||||
|
'comment', 'is_accepted', "is_active", 'session_online',
|
||||||
|
'is_alive'
|
||||||
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_session_online(obj):
|
def get_session_online(obj):
|
||||||
|
|
|
@ -89,7 +89,7 @@ function initTable() {
|
||||||
],
|
],
|
||||||
ajax_url: '{% url "api-terminal:terminal-list" %}',
|
ajax_url: '{% url "api-terminal:terminal-list" %}',
|
||||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"},
|
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"},
|
||||||
{data: "session_online"}, {data: "is_accepted" }, {data: 'is_alive'}, {data: "id"}],
|
{data: "session_online"}, {data: "is_active" }, {data: 'is_alive'}, {data: "id"}],
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
|
|
|
@ -20,6 +20,7 @@ urlpatterns = [
|
||||||
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$',
|
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$',
|
||||||
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
|
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
|
||||||
name='session-replay'),
|
name='session-replay'),
|
||||||
|
url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key')
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -73,6 +73,7 @@ class TerminalAcceptView(AdminUserRequiredMixin, JSONResponseMixin, UpdateView):
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
terminal = form.save()
|
terminal = form.save()
|
||||||
|
terminal.create_app_user()
|
||||||
terminal.is_accepted = True
|
terminal.is_accepted = True
|
||||||
terminal.is_active = True
|
terminal.is_active = True
|
||||||
terminal.save()
|
terminal.save()
|
||||||
|
|
|
@ -28,13 +28,13 @@ class User(AbstractUser):
|
||||||
('App', 'Application')
|
('App', 'Application')
|
||||||
)
|
)
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
username = models.CharField(max_length=20, unique=True, verbose_name=_('Username'))
|
username = models.CharField(max_length=128, unique=True, verbose_name=_('Username'))
|
||||||
name = models.CharField(max_length=20, verbose_name=_('Name'))
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||||
email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email'))
|
email = models.EmailField(max_length=128, unique=True, verbose_name=_('Email'))
|
||||||
groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group'))
|
groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group'))
|
||||||
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
|
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
|
||||||
avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
|
avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
|
||||||
wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat'))
|
wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat'))
|
||||||
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
|
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
|
||||||
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
|
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
|
||||||
secret_key_otp = models.CharField(max_length=16, blank=True)
|
secret_key_otp = models.CharField(max_length=16, blank=True)
|
||||||
|
@ -212,7 +212,7 @@ class User(AbstractUser):
|
||||||
def create_app_user(cls, name, comment):
|
def create_app_user(cls, name, comment):
|
||||||
from . import AccessKey
|
from . import AccessKey
|
||||||
app = cls.objects.create(
|
app = cls.objects.create(
|
||||||
username=name, name=name, email='%s@local.domain'.format(),
|
username=name, name=name, email='{}@local.domain'.format(name),
|
||||||
is_active=False, role='App', enable_otp=False, comment=comment,
|
is_active=False, role='App', enable_otp=False, comment=comment,
|
||||||
is_first_login=False, created_by='System'
|
is_first_login=False, created_by='System'
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,11 @@ DEBUG = CONFIG.DEBUG
|
||||||
LOG_LEVEL = CONFIG.LOG_LEVEL
|
LOG_LEVEL = CONFIG.LOG_LEVEL
|
||||||
WORKERS = 4
|
WORKERS = 4
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.join(BASE_DIR, "data", "static"))
|
||||||
|
os.makedirs(os.path.join(BASE_DIR, "data", "media"))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def start_gunicorn():
|
def start_gunicorn():
|
||||||
print("# Start Gunicorn WSGI HTTP Server")
|
print("# Start Gunicorn WSGI HTTP Server")
|
||||||
|
|
Loading…
Reference in New Issue