mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: 提升服务注册安全性
							parent
							
								
									9ed822bb3e
								
							
						
					
					
						commit
						b55000663e
					
				| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
import os
 | 
			
		||||
import requests
 | 
			
		||||
from httpsig.requests_auth import HTTPSignatureAuth
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_drf_ak():
 | 
			
		||||
    KEY_ID = os.environ.get('KEY_ID') or ''
 | 
			
		||||
    SECRET = os.environ.get('KEY_SECRET') or ''
 | 
			
		||||
 | 
			
		||||
    signature_headers = ['(request-target)', 'date']
 | 
			
		||||
    now = datetime.datetime.now()
 | 
			
		||||
    headers = {
 | 
			
		||||
      'Host': 'localhost:8000',
 | 
			
		||||
      'Accept': 'application/json',
 | 
			
		||||
      'Date': now.strftime('%a, %d %b %Y %H:%M:%S GMT'),
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    # url = 'http://localhost:8080/api/v1/assets/assets/?limit=100'
 | 
			
		||||
    url = 'http://localhost:8080/api/v1/users/users/?limit=100'
 | 
			
		||||
    
 | 
			
		||||
    auth = HTTPSignatureAuth(key_id=KEY_ID, secret=SECRET,
 | 
			
		||||
                           algorithm='hmac-sha256',
 | 
			
		||||
                           headers=signature_headers)
 | 
			
		||||
    req = requests.get(url, auth=auth, headers=headers)
 | 
			
		||||
    print(req.content)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    test_drf_ak()
 | 
			
		||||
| 
						 | 
				
			
			@ -27,10 +27,23 @@ class IsServiceAccount(IsValidUser):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class WithBootstrapToken(permissions.BasePermission):
 | 
			
		||||
    def check_can_register(self):
 | 
			
		||||
        enabled = settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION
 | 
			
		||||
        if enabled == 'auto':
 | 
			
		||||
            return time.time() - settings.JUMPSERVER_UPTIME < 300
 | 
			
		||||
        elif enabled:
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def has_permission(self, request, view):
 | 
			
		||||
        authorization = request.META.get('HTTP_AUTHORIZATION', '')
 | 
			
		||||
        if not authorization:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        if not self.check_can_register():
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        request_bootstrap_token = authorization.split()[-1]
 | 
			
		||||
        return settings.BOOTSTRAP_TOKEN == request_bootstrap_token
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -568,7 +568,7 @@ class Config(dict):
 | 
			
		|||
        'SECURITY_COMMAND_BLACKLIST': [
 | 
			
		||||
            'reboot', 'shutdown', 'poweroff', 'halt', 'dd', 'half', 'top'
 | 
			
		||||
        ],
 | 
			
		||||
        'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True,
 | 
			
		||||
        'SECURITY_SERVICE_ACCOUNT_REGISTRATION': 'auto',
 | 
			
		||||
        'SECURITY_VIEW_AUTH_NEED_MFA': True,
 | 
			
		||||
        'SECURITY_MAX_IDLE_TIME': 30,
 | 
			
		||||
        'SECURITY_MAX_SESSION_TIME': 24,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
import time
 | 
			
		||||
from .base import (
 | 
			
		||||
    REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, REDIS_SSL_REQUIRED, REDIS_USE_SSL,
 | 
			
		||||
    REDIS_PROTOCOL, REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, REDIS_SENTINEL_PASSWORD,
 | 
			
		||||
| 
						 | 
				
			
			@ -197,3 +197,5 @@ PIICO_DEVICE_ENABLE = CONFIG.PIICO_DEVICE_ENABLE
 | 
			
		|||
PIICO_DRIVER_PATH = CONFIG.PIICO_DRIVER_PATH
 | 
			
		||||
 | 
			
		||||
LEAK_PASSWORD_DB_PATH = CONFIG.LEAK_PASSWORD_DB_PATH
 | 
			
		||||
 | 
			
		||||
JUMPSERVER_UPTIME = int(time.time())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,11 @@ class TerminalSettingSerializer(serializers.Serializer):
 | 
			
		|||
        ('25', '25'),
 | 
			
		||||
        ('50', '50'),
 | 
			
		||||
    )
 | 
			
		||||
    SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField(
 | 
			
		||||
    SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.ChoiceField(
 | 
			
		||||
        choices=[
 | 
			
		||||
            ('auto', _('Auto(Enabled for the first 5 minutes after startup, then disabled.)')), 
 | 
			
		||||
            (True, _('Enable')), (False, _('Disable'))
 | 
			
		||||
        ],
 | 
			
		||||
        required=True, label=_('Registration'),
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            "Allow component register, after all component setup, you should disable this for security"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,12 +85,6 @@ class TerminalRegistrationApi(generics.CreateAPIView):
 | 
			
		|||
    permission_classes = [WithBootstrapToken]
 | 
			
		||||
    http_method_names = ['post']
 | 
			
		||||
 | 
			
		||||
    def create(self, request, *args, **kwargs):
 | 
			
		||||
        if not settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION:
 | 
			
		||||
            data = {"error": "service account registration disabled"}
 | 
			
		||||
            return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
        return super().create(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EncryptedTerminalConfig(generics.CreateAPIView):
 | 
			
		||||
    serializer_class = serializers.EncryptedConfigSerializer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue