Compare commits

...

39 Commits

Author SHA1 Message Date
ibuler
7c08582e7d Merge branch 'master' into v2.0 2020-07-08 16:14:19 +08:00
ibuler
3555fe1c20 Merge branch 'v2.0' of github.com:jumpserver/jumpserver into v2.0 2020-07-08 16:14:06 +08:00
ibuler
4a1045ba81 ci(build&release): 自动化构建发布 2020-07-08 15:58:57 +08:00
ibuler
7fc3218010 添加example api 2020-07-08 15:58:57 +08:00
ibuler
0dd4c8adc2 Merge branch 'v2.0' of github.com:jumpserver/jumpserver into v2.0 2020-07-08 15:48:05 +08:00
ibuler
ce7edc1612 ci(release): 修改 release 使用的tag,而不是自动生成的 2020-07-08 10:36:43 +08:00
ibuler
23ef185b7e fix(build): 修改调用action jumpserver/action-build-upload-asset的参数 2020-07-07 14:30:34 +08:00
ibuler
6b16aa6bc0 ci(build): 修改 构建脚本
- sed 在不同系统下表现不同
2020-07-07 13:52:50 +08:00
ibuler
43741dc9b2 ci(build): 修改 workflow
- 修改使用action jumpserver/action-build-upload-assets
2020-07-07 13:38:26 +08:00
ibuler
18174e2867 fix(build): 修稿构建 2020-07-07 13:28:59 +08:00
ibuler
3077d11483 ci(release&build): 添加 github workflows, 自动构建 release
- 添加 utils/build.sh 脚本,构建后放到 release 目录中
- 当 push tags时,自动创建 Release Draft
- 自动生成 Release Change Log
- 自动构建包,上传到 Release Assets
2020-07-07 13:03:48 +08:00
xinwen
a9626c2b39 Merge pull request #4223 from jumpserver/update-add-filter
[Update] assets/gathered_user 添加过滤字段
2020-07-01 17:32:58 +08:00
xinwen
b265fad50f [Update] assets/gathered_user 添加过滤字段 2020-07-01 17:21:00 +08:00
BaiJiangJie
f40b50dddd Merge pull request #4209 from jumpserver/ftp_log_order
fix:修改 ftp 日志按开始日期排序
2020-07-01 15:02:44 +08:00
xinwen
0d6255b07f Merge pull request #4218 from jumpserver/system-user-add-filter
System user add filter
2020-07-01 15:01:07 +08:00
xinwen
06b02cfcfd [Update] 系统用户添加过滤字段 2020-07-01 14:57:52 +08:00
jym503558564
a7e1ed6f03 fix:修改 ftp 日志按开始日期排序 2020-07-01 11:04:42 +08:00
xinwen
1c6f89519a Merge pull request #4201 from jumpserver/fix-i18n
Fix i18n
2020-06-30 14:21:44 +08:00
xinwen
24d093747f [Fix] X-Pack/云管中心 i18n 2020-06-30 14:18:21 +08:00
老广
8c4e9720d3 Merge pull request #4183 from jumpserver/fix_template
docs(github): 修改 github issue 模板
2020-06-28 15:22:41 +08:00
ibuler
d43709f584 docs(github): 修改 github issue 模板
更改版本号说明,1.4及之前不再提供支持
2020-06-28 15:17:15 +08:00
BaiJiangJie
89496baae5 Merge pull request #4148 from jumpserver/v2.0
V2.0
2020-06-28 10:47:56 +08:00
BaiJiangJie
ea6d995f55 Merge pull request #4147 from jumpserver/v2.0_bugfix_csv
[Update] 修改csv导出,最大限制条目数从100->10000条
2020-06-28 10:46:31 +08:00
Bai
cf6aba1f38 [Update] 修改csv导出,最大限制条目数从100->10000条 2020-06-28 10:43:47 +08:00
老广
2acc1dc875 Merge pull request #4134 from jumpserver/fix-mfa-1.5
Fix mfa 1.5
2020-06-22 19:05:15 +08:00
xinwen
32ed43ba7b Merge branch 'v2.0' into fix-mfa-1.5 2020-06-22 19:04:42 +08:00
xinwen
3e993fd044 [Update] 调整MFA绑定策略 V2 2020-06-22 19:02:14 +08:00
xinwen
005573b53b [Fix] 重新绑定 MFA 的漏洞 2020-06-22 18:03:45 +08:00
老广
e04e31eb30 Merge pull request #4129 from jumpserver/readme
feat: readme 添加docker pull
2020-06-22 12:08:28 +08:00
ibuler
ff747f9e42 feat: readme 添加docker pull 2020-06-22 12:06:42 +08:00
BaiJiangJie
c4bd093fd7 Merge pull request #4126 from jumpserver/v2.0
V2.0
2020-06-20 19:26:12 +08:00
BaiJiangJie
408b2d6dbd Merge pull request #4125 from jumpserver/v2.0_bugfix
v2.0 添加改密计划安全模式配置项
2020-06-20 19:24:17 +08:00
BaiJiangJie
ebc63b9410 Merge pull request #4123 from jumpserver/v1.5_bugfix
[Update] 添加改密计划安全模式配置项
2020-06-20 16:20:53 +08:00
Michael Bai
f1e5c7c2bb 添加改密计划安全模式配置项 2020-06-20 16:18:58 +08:00
Michael Bai
fcb0aefe3c 更改改密计划安全模式配置项名 2020-06-20 15:47:39 +08:00
Bai
29666cc8d3 [Update] 添加改密计划安全模式配置项 2020-06-19 20:41:51 +08:00
xinwen
1d640eccf6 [Fix] /opt/jumpserver/apps/jumpserver/views/index.py redirect(assets:user-asset-list) (#4121) 2020-06-19 18:28:43 +08:00
ibuler
7548bb8976 Merge branch 'dev' of github.com:jumpserver/jumpserver into dev 2020-06-17 11:33:57 +08:00
ibuler
8ffa5e0aec 添加example api 2020-06-16 20:11:50 +08:00
22 changed files with 240 additions and 37 deletions

View File

@@ -2,7 +2,7 @@
##### 使用版本 ##### 使用版本
[请提供你使用的Jumpserver版本 1.x.x 注: 0.3.x不再提供支持] [请提供你使用的JumpServer版本 如 2.0.1 注: 1.4及以下版本不再提供支持]
##### 问题复现步骤 ##### 问题复现步骤
1. [步骤1] 1. [步骤1]

44
.github/release-config.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: '🌱 新功能 Features'
labels:
- 'feature'
- 'enhancement'
- 'feat'
- '新功能'
- title: '🚀 性能优化 Optimization'
labels:
- 'perf'
- 'opt'
- 'refactor'
- 'Optimization'
- '优化'
- title: '🐛 Bug修复 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 其它 Maintenance'
labels:
- 'chore'
- 'docs'
exclude-labels:
- 'no'
- '无需处理'
- 'wontfix'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
template: |
## 版本变化 Whats Changed
$CHANGES

46
.github/workflows/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release And Upload assets
jobs:
create-realese:
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Get version
id: get_version
run: |
TAG=$(basename ${GITHUB_REF})
VERSION=${TAG/v/}
echo "::set-output name=TAG::$TAG"
echo "::set-output name=VERSION::$VERSION"
- name: Create Release
id: create_release
uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config-name: release-config.yml
version: ${{ steps.get_version.outputs.TAG }}
tag: ${{ steps.get_version.outputs.TAG }}
build-and-release:
needs: create-realese
name: Build and Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build it and upload
uses: jumpserver/action-build-upload-assets@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-realese.outputs.upload_url }}

4
.gitignore vendored
View File

@@ -35,4 +35,6 @@ docs/_build/
xpack xpack
logs/* logs/*
### Vagrant ### ### Vagrant ###
.vagrant/ .vagrant/
release/*
releashe

View File

@@ -2,6 +2,7 @@
[![Python3](https://img.shields.io/badge/python-3.6-green.svg?style=plastic)](https://www.python.org/) [![Python3](https://img.shields.io/badge/python-3.6-green.svg?style=plastic)](https://www.python.org/)
[![Django](https://img.shields.io/badge/django-2.2-brightgreen.svg?style=plastic)](https://www.djangoproject.com/) [![Django](https://img.shields.io/badge/django-2.2-brightgreen.svg?style=plastic)](https://www.djangoproject.com/)
[![Docker Pulls](https://img.shields.io/docker/pulls/jumpserver/jms_all.svg)](https://hub.docker.com/u/jumpserver)
JumpServer 是全球首款开源的堡垒机,使用 GNU GPL v2.0 开源协议,是符合 4A 规范的运维安全审计系统。 JumpServer 是全球首款开源的堡垒机,使用 GNU GPL v2.0 开源协议,是符合 4A 规范的运维安全审计系统。

View File

@@ -18,5 +18,5 @@ class GatheredUserViewSet(OrgModelViewSet):
permission_classes = [IsOrgAdmin] permission_classes = [IsOrgAdmin]
extra_filter_backends = [AssetRelatedByNodeFilterBackend] extra_filter_backends = [AssetRelatedByNodeFilterBackend]
filter_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname'] filter_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname', 'asset_id']
search_fields = ['username', 'asset__ip', 'asset__hostname'] search_fields = ['username', 'asset__ip', 'asset__hostname']

View File

@@ -28,7 +28,7 @@ class SystemUserViewSet(OrgBulkModelViewSet):
System user api set, for add,delete,update,list,retrieve resource System user api set, for add,delete,update,list,retrieve resource
""" """
model = SystemUser model = SystemUser
filter_fields = ("name", "username") filter_fields = ("name", "username", "protocol")
search_fields = filter_fields search_fields = filter_fields
serializer_class = serializers.SystemUserSerializer serializer_class = serializers.SystemUserSerializer
serializer_classes = { serializer_classes = {

View File

@@ -27,6 +27,7 @@ class FTPLogViewSet(CreateModelMixin,
] ]
filter_fields = ['user', 'asset', 'system_user', 'filename'] filter_fields = ['user', 'asset', 'system_user', 'filename']
search_fields = filter_fields search_fields = filter_fields
ordering = ['-date_start']
class UserLoginLogViewSet(ListModelMixin, CommonGenericViewSet): class UserLoginLogViewSet(ListModelMixin, CommonGenericViewSet):

View File

@@ -30,7 +30,7 @@ class JMSCSVRender(BaseRenderer):
@staticmethod @staticmethod
def _gen_table(data, fields): def _gen_table(data, fields):
data = data[:100] data = data[:10000]
yield ['*{}'.format(f.label) if f.required else f.label for f in fields] yield ['*{}'.format(f.label) if f.required else f.label for f in fields]
for item in data: for item in data:

View File

@@ -10,3 +10,7 @@ class HttpResponseTemporaryRedirect(HttpResponse):
def __init__(self, redirect_to): def __init__(self, redirect_to):
HttpResponse.__init__(self) HttpResponse.__init__(self)
self['Location'] = iri_to_uri(redirect_to) self['Location'] = iri_to_uri(redirect_to)
def get_remote_addr(request):
return request.META.get("HTTP_X_FORWARDED_HOST") or request.META.get("REMOTE_ADDR")

View File

@@ -259,7 +259,8 @@ class Config(dict):
'WINDOWS_SKIP_ALL_MANUAL_PASSWORD': False, 'WINDOWS_SKIP_ALL_MANUAL_PASSWORD': False,
'ORG_CHANGE_TO_URL': '', 'ORG_CHANGE_TO_URL': '',
'LANGUAGE_CODE': 'zh', 'LANGUAGE_CODE': 'zh',
'TIME_ZONE': 'Asia/Shanghai' 'TIME_ZONE': 'Asia/Shanghai',
'CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED': True
} }
def compatible_auth_openid_of_key(self): def compatible_auth_openid_of_key(self):

View File

@@ -86,7 +86,11 @@ TASK_LOG_KEEP_DAYS = CONFIG.TASK_LOG_KEEP_DAYS
ORG_CHANGE_TO_URL = CONFIG.ORG_CHANGE_TO_URL ORG_CHANGE_TO_URL = CONFIG.ORG_CHANGE_TO_URL
WINDOWS_SKIP_ALL_MANUAL_PASSWORD = CONFIG.WINDOWS_SKIP_ALL_MANUAL_PASSWORD WINDOWS_SKIP_ALL_MANUAL_PASSWORD = CONFIG.WINDOWS_SKIP_ALL_MANUAL_PASSWORD
AUTH_EXPIRED_SECONDS = 60 * 5
# XPACK # XPACK
XPACK_LICENSE_IS_VALID = DYNAMIC.XPACK_LICENSE_IS_VALID XPACK_LICENSE_IS_VALID = DYNAMIC.XPACK_LICENSE_IS_VALID
LOGO_URLS = DYNAMIC.LOGO_URLS LOGO_URLS = DYNAMIC.LOGO_URLS
CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED = CONFIG.CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED

View File

@@ -1,5 +1,4 @@
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import redirect from django.shortcuts import redirect
from common.permissions import PermissionsMixin, IsValidUser from common.permissions import PermissionsMixin, IsValidUser
@@ -12,17 +11,3 @@ class IndexView(PermissionsMixin, TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return redirect('/ui/') return redirect('/ui/')
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
if request.user.is_common_user:
return redirect('assets:user-asset-list')
return super(IndexView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'app': _("Dashboard"),
})
return context

Binary file not shown.

View File

@@ -3755,7 +3755,7 @@ msgstr "腾讯云"
#: xpack/plugins/cloud/serializers.py:53 #: xpack/plugins/cloud/serializers.py:53
msgid "History count" msgid "History count"
msgstr "用户数量" msgstr "执行次数"
#: xpack/plugins/cloud/serializers.py:54 #: xpack/plugins/cloud/serializers.py:54
msgid "Instance count" msgid "Instance count"

View File

@@ -5,8 +5,8 @@ import re
import pyotp import pyotp
import base64 import base64
import logging import logging
import time
from django.http import Http404
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.cache import cache from django.core.cache import cache
@@ -333,3 +333,15 @@ def get_source_choices():
if settings.AUTH_CAS: if settings.AUTH_CAS:
choices.append((User.SOURCE_CAS, choices_all[User.SOURCE_CAS])) choices.append((User.SOURCE_CAS, choices_all[User.SOURCE_CAS]))
return choices return choices
def is_auth_time_valid(session, key):
return True if session.get(key, 0) > time.time() else False
def is_auth_password_time_valid(session):
return is_auth_time_valid(session, 'auth_password_expired_at')
def is_auth_otp_time_valid(session):
return is_auth_time_valid(session, 'auth_opt_expired_at')

View File

@@ -1,4 +1,5 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
import time
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy, reverse
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@@ -6,13 +7,17 @@ from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.contrib.auth import logout as auth_logout from django.contrib.auth import logout as auth_logout
from django.conf import settings from django.conf import settings
from django.http.response import HttpResponseForbidden
from common.utils import get_logger from authentication.mixins import AuthMixin
from users.models import User
from common.utils import get_logger, get_object_or_none
from common.permissions import IsValidUser from common.permissions import IsValidUser
from ... import forms from ... import forms
from .password import UserVerifyPasswordView from .password import UserVerifyPasswordView
from ...utils import ( from ...utils import (
generate_otp_uri, check_otp_code, get_user_or_pre_auth_user, generate_otp_uri, check_otp_code, get_user_or_pre_auth_user,
is_auth_password_time_valid, is_auth_otp_time_valid
) )
__all__ = [ __all__ = [
@@ -46,11 +51,50 @@ class UserOtpEnableInstallAppView(TemplateView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserOtpEnableBindView(TemplateView, FormView): class UserOtpEnableBindView(AuthMixin, TemplateView, FormView):
template_name = 'users/user_otp_enable_bind.html' template_name = 'users/user_otp_enable_bind.html'
form_class = forms.UserCheckOtpCodeForm form_class = forms.UserCheckOtpCodeForm
success_url = reverse_lazy('authentication:user-otp-settings-success') success_url = reverse_lazy('authentication:user-otp-settings-success')
def get(self, request, *args, **kwargs):
if self._check_can_bind():
return super().get(request, *args, **kwargs)
return HttpResponseForbidden()
def post(self, request, *args, **kwargs):
if self._check_can_bind():
return super().post(request, *args, **kwargs)
return HttpResponseForbidden()
def _check_authenticated_user_can_bind(self):
user = self.request.user
session = self.request.session
if not user.mfa_enabled:
return is_auth_password_time_valid(session)
if not user.otp_secret_key:
return is_auth_password_time_valid(session)
return is_auth_otp_time_valid(session)
def _check_unauthenticated_user_can_bind(self):
session_user = None
if not self.request.session.is_empty():
user_id = self.request.session.get('user_id')
session_user = get_object_or_none(User, pk=user_id)
if session_user:
if all((is_auth_password_time_valid(self.request.session), session_user.mfa_enabled, not session_user.otp_secret_key)):
return True
return False
def _check_can_bind(self):
if self.request.user.is_authenticated:
return self._check_authenticated_user_can_bind()
else:
return self._check_unauthenticated_user_can_bind()
def form_valid(self, form): def form_valid(self, form):
otp_code = form.cleaned_data.get('otp_code') otp_code = form.cleaned_data.get('otp_code')
otp_secret_key = self.request.session.get('otp_secret_key', '') otp_secret_key = self.request.session.get('otp_secret_key', '')
@@ -116,6 +160,7 @@ class UserOtpUpdateView(FormView):
valid = user.check_mfa(otp_code) valid = user.check_mfa(otp_code)
if valid: if valid:
self.request.session['auth_opt_expired_at'] = time.time() + settings.AUTH_EXPIRED_SECONDS
return super().form_valid(form) return super().form_valid(form)
else: else:
error = _('MFA code invalid, or ntp sync server time') error = _('MFA code invalid, or ntp sync server time')

View File

@@ -1,8 +1,10 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
import time
from django.conf import settings
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.generic.edit import UpdateView, FormView from django.views.generic.edit import UpdateView, FormView
from django.contrib.auth import logout as auth_logout from django.contrib.auth import logout as auth_logout
@@ -76,6 +78,7 @@ class UserVerifyPasswordView(FormView):
user.save() user.save()
self.request.session['user_id'] = str(user.id) self.request.session['user_id'] = str(user.id)
self.request.session['auth_password'] = 1 self.request.session['auth_password'] = 1
self.request.session['auth_password_expired_at'] = time.time() + settings.AUTH_EXPIRED_SECONDS
return redirect(self.get_success_url()) return redirect(self.get_success_url())
def get_success_url(self): def get_success_url(self):

View File

@@ -1,11 +0,0 @@
#!/bin/bash
#
version=$1
if [ -z "$version" ];then
echo "Usage: sh build version"
exit
fi
docker build -t jumpserver/jumpserver:$version .

28
utils/build.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
#
# 该build基于registry.fit2cloud.com/public/python:3
utils_dir=$(pwd)
project_dir=$(dirname "$utils_dir")
release_dir=${project_dir}/release
# 安装依赖包
command -v git || yum -y install git
# 打包
cd "${project_dir}" || exit 3
rm -rf "${release_dir:?}/*"
to_dir="${release_dir}/jumpserver"
mkdir -p "${to_dir}"
git archive --format tar HEAD | tar x -C "${to_dir}"
if [[ $(uname) == 'Darwin' ]];then
alias sedi="sed -i ''"
else
alias sedi='sed -i'
fi
# 修改版本号文件
if [[ -n ${VERSION} ]]; then
sedi "s@VERSION = .*@VERSION = \"${VERSION}\"@g" "${to_dir}/apps/jumpserver/const.py"
fi

12
utils/build_docker.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
#
utils_dir=$(dirname "$0")
project_dir=$(dirname "${utils_dir}")
version=$1
if [ -z "$version" ]; then
echo "Usage: sh build version"
exit
fi
cd "${project_dir}" && docker build -t "jumpserver/jumpserver:${version}" .

26
utils/example_api.py Normal file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env python
import requests
# 私有token页面上目前不允许创建只能后台生成见 https://docs.jumpserver.org/zh/master/dev/rest_api/
private_token = '10659d70a223235b8f76d45a3023eca1147488d7'
def do_request(url, data=None, method='get', params=None, org_id=''):
authorization = 'Token {}'.format(private_token)
headers = {'Authorization': authorization, 'Content-Type': 'application/json'}
if org_id:
headers['X-JMS-ORG'] = org_id
resp = requests.request(method=method, url=url, data=data, params=params, headers=headers)
return resp
def get_assets_list():
url = 'http://localhost:8080/api/v1/assets/assets/?limit=10'
resp = do_request(url)
print(resp.status_code)
print(resp.json())
print(resp)
if __name__ == '__main__':
get_assets_list()