Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
cfef3744
Commit
cfef3744
authored
Sep 24, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update ssh server
parent
0d4ca971
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
127 additions
and
61 deletions
+127
-61
hands.py
apps/terminal/hands.py
+2
-1
host_rsa_key
apps/terminal/keys/host_rsa_key
+27
-0
server.py
apps/terminal/server.py
+69
-59
models.py
apps/users/models.py
+6
-0
utils.py
apps/users/utils.py
+19
-1
config-example.py
config-example.py
+4
-0
No files found.
apps/terminal/hands.py
View file @
cfef3744
...
@@ -2,4 +2,5 @@
...
@@ -2,4 +2,5 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
from
users.utils
import
ssh_key_gen
from
users.utils
import
ssh_key_gen
,
check_user_is_valid
apps/terminal/keys/host_rsa_key
0 → 100644
View file @
cfef3744
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAxreMFq9tp1hb2NOIkV7PqeyfS0GTJSfW2WcXuqkGPSVtPdYw
cJRY/s5eBn0KbO6JVj9yfwXNTKdnq1ODuuJDMnhTWXq1x7VICcou/69kFdSGiAzl
wfYP6LATEMCmpFRVi5UZip7SWopLE1JEw79nYWrbhUpDOpGTRKoIxoz+Uvg0h15G
pec3faL7PXj/J6j9pis44N1PCMBY3DVFPLopVcFpElbzwScNvZGBes90JoKLsqfD
Vjc9PUPjYjck9NFR6Xy0D5Gnw9MD5o0yK1l+3sibXjFBMOxA7aNxIlMhXQGol8R7
3HBHWo/+Bwct3w1c8cPKfdPd8jGn3eWGYxupvQIDAQABAoIBADuyWDtYaDClsrHo
mlZRjUEW/KO3B2VaGoklF1PUAzPLUo4JEnQ/nJyvkj+QwNkIr+lhFhxiudIVWGd3
p1M1Ncqrqx5uZr2gEAwg2Q2muwJz3hZxCXTDXvQgMRoPRgCH9UsBd7LVE4xvjy42
wMGtdnkliNz5+khWA0/VZN2A7cYukrKzPwnhEMSrzYfnRwcOvp8pDp++Yjs3ZhQL
8+sgL1UDap5p5QZSQ98qJGNwmePAlTig+2Z5HvF+zussK2N7g5AcfghQFo5vCw/L
PXYtIfBH+Tv+6s7vMBMSLpbDcAZsxR9gDVUQi252Gu/nWClCzH3Kgu5ormHSOkYO
F6/n5AECgYEA69anuf52KWwYypVA73HiUbuzOdeuc1Br+s0uzOvpFX0HaqDxo8dm
N7FtUj/WnoqFivQrsrt4LpIzKn1XPNk7wMnwIZAQHNEI8sy7LBVh3RJOP2ZC2329
ZHWxB3EVQ8Q5MbZy/AOn92UYwz8xIb0LweGYnHZlMp+xtOhdUR0/Z90CgYEA17R8
EOeErksBRHotrEk0jLx+rrhK0JGcpXo/Dw6AOEp936DgHlqbkUURT2ejDOSQY/dN
7i4WeFJCVfFRNMbsitWxNmAdl3NJ5C2bV+7sz+oZfo5zP/e1RYCNLVjLxLYOHQ37
GWwAlQr6fPcIZMCaPH+xq/0WSqcP96Lu6G0VG2ECgYB1XtcKkcFszAdqiu1OPXdN
BgUkfFqtuRCEOSlZgu71aswOHRslT09n2D13+Z1uObJMfUhiIzqkss4UD10jQ1mh
kN6ZVYEvVjkF3S4pulqCE2It207avbFMFeaMtZLHrxhnzU1cbtVhIkc4pHJnQBZh
30x8Uc/7ac6fIiWPAOdVYQKBgCi8rEWhA7zK64VcMa388VC29JHYukBjj5rs2GXm
ji6TWuxV/J2e7QxlZ9yALRntPJu0g+I8j//PQTnr5jM6ckfSDbLAOjZ1DnpqZpEX
zV+CzafKDVgCVxi2K3Np9qnC3C1+i3KEpCOBvEbHfK1Sdo6AazSZCpG0tV5GRipd
F4RhAoGAUJBoemipDjFoLSD3cpKpUXHIc6eieAI1GwYiL4CVugrvj5gO2B5c5yYb
3E8VWfuEHbBg0rmZIQ0sQf2ospZha7WBNhg9WB016aHyeZTIuHchfU4y3l2Jl8Re
enz4SSi6ZR6hgbJ9XzeiI+UTcDEuUzDUy9YktREuIBmMPXm7u5s=
-----END RSA PRIVATE KEY-----
apps/terminal/server.py
View file @
cfef3744
...
@@ -3,19 +3,6 @@
...
@@ -3,19 +3,6 @@
#
#
import
sys
import
sys
import
os
import
os
import
django
BASE_DIR
=
os
.
path
.
dirname
(
__file__
)
APP_DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
BASE_DIR
))
sys
.
path
.
append
(
APP_DIR
)
os
.
environ
[
'DJANGO_SETTINGS_MODULE'
]
=
'jumpserver.settings'
try
:
django
.
setup
()
except
IndexError
:
pass
import
base64
import
base64
from
binascii
import
hexlify
from
binascii
import
hexlify
import
sys
import
sys
...
@@ -30,14 +17,24 @@ import socket
...
@@ -30,14 +17,24 @@ import socket
import
select
import
select
import
errno
import
errno
import
paramiko
import
paramiko
import
django
from
paramiko.py3compat
import
b
,
u
,
decodebytes
from
paramiko.py3compat
import
b
,
u
,
decodebytes
from
.hands
import
ssh_key_gen
BASE_DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
__file__
))
APP_DIR
=
os
.
path
.
dirname
(
BASE_DIR
)
sys
.
path
.
append
(
APP_DIR
)
os
.
environ
[
'DJANGO_SETTINGS_MODULE'
]
=
'jumpserver.settings'
try
:
django
.
setup
()
except
IndexError
:
pass
paramiko
.
util
.
log_to_file
(
'demo_server.log'
)
from
django.conf
import
settings
from
common.utils
import
get_logger
from
hands
import
ssh_key_gen
,
check_user_is_valid
host_key
=
paramiko
.
RSAKey
(
filename
=
'test_rsa.key'
)
logger
=
get_logger
(
__name__
)
class
SSHService
(
paramiko
.
ServerInterface
):
class
SSHService
(
paramiko
.
ServerInterface
):
...
@@ -46,30 +43,31 @@ class SSHService(paramiko.ServerInterface):
...
@@ -46,30 +43,31 @@ class SSHService(paramiko.ServerInterface):
# b'KDqIexkgHAfID/6mqvmnSJf0b5W8v5h2pI/stOSwTQ+pxVhwJ9ctYDhRSlF0iT'
# b'KDqIexkgHAfID/6mqvmnSJf0b5W8v5h2pI/stOSwTQ+pxVhwJ9ctYDhRSlF0iT'
# b'UWT10hcuO4Ks8=')
# b'UWT10hcuO4Ks8=')
# good_pub_key = paramiko.RSAKey(data=decodebytes(data))
# good_pub_key = paramiko.RSAKey(data=decodebytes(data))
# host_key = paramiko.RSAKey(filename='test_rsa.key')
ssh_key_path
=
os
.
path
.
join
(
BASE_DIR
,
'keys'
,
'ssh_host_key'
)
host_key_path
=
os
.
path
.
join
(
BASE_DIR
,
'keys'
,
'host_rsa_key'
)
ssh_pub_key_path
=
ssh_key_path
+
'.pub'
def
__init__
(
self
):
def
__init__
(
self
):
self
.
event
=
threading
.
Event
()
self
.
event
=
threading
.
Event
()
self
.
user
=
None
@classmethod
def
host_key
(
cls
):
return
cls
.
get_host_key
()
@classmethod
@classmethod
def
get_host_key
(
cls
):
def
get_host_key
(
cls
):
if
os
.
path
.
isfile
(
cls
.
ssh_pub_key_path
):
logger
.
debug
(
"Get ssh server host key"
)
with
open
(
cls
.
ssh_pub_key_path
)
as
f
:
if
not
os
.
path
.
isfile
(
cls
.
host_key_path
):
ssh_pub_key
=
f
.
read
()
cls
.
host_key_gen
()
else
:
return
paramiko
.
RSAKey
(
filename
=
cls
.
host_key_path
)
ssh_key
,
ssh_pub_key
=
cls
.
host_key_gen
()
return
ssh_pub_key
@classmethod
@classmethod
def
host_key_gen
(
cls
):
def
host_key_gen
(
cls
):
logger
.
debug
(
"Generate ssh server host key"
)
ssh_key
,
ssh_pub_key
=
ssh_key_gen
()
ssh_key
,
ssh_pub_key
=
ssh_key_gen
()
with
open
(
cls
.
ssh_key_path
,
'w'
)
as
f
:
with
open
(
cls
.
host_key_path
,
'w'
)
as
f
:
with
open
(
cls
.
ssh_pub_key_path
,
'w'
)
as
f2
:
f
.
write
(
ssh_key
)
f
.
write
(
ssh_key
)
f2
.
write
(
ssh_pub_key
)
return
ssh_key
,
ssh_pub_key
def
check_channel_request
(
self
,
kind
,
chanid
):
def
check_channel_request
(
self
,
kind
,
chanid
):
if
kind
==
'session'
:
if
kind
==
'session'
:
...
@@ -77,18 +75,30 @@ class SSHService(paramiko.ServerInterface):
...
@@ -77,18 +75,30 @@ class SSHService(paramiko.ServerInterface):
return
paramiko
.
OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
return
paramiko
.
OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
def
check_auth_password
(
self
,
username
,
password
):
def
check_auth_password
(
self
,
username
,
password
):
if
(
username
==
'robey'
)
and
(
password
==
'foo'
):
self
.
user
=
check_user_is_valid
(
username
=
username
,
password
=
password
)
if
self
.
user
:
logger
.
info
(
'User:
%
s password auth passed'
%
username
)
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_SUCCESSFUL
else
:
logger
.
warning
(
'User:
%
s password auth failed'
%
username
)
return
paramiko
.
AUTH_FAILED
return
paramiko
.
AUTH_FAILED
def
check_auth_publickey
(
self
,
username
,
key
):
def
check_auth_publickey
(
self
,
username
,
public_key
):
print
(
'Auth attempt with key: '
+
u
(
hexlify
(
key
.
get_fingerprint
())))
self
.
user
=
check_user_is_valid
(
username
=
username
,
public_key
=
public_key
)
if
(
username
==
'robey'
)
and
(
key
==
self
.
good_pub_key
):
if
self
.
user
:
logger
.
info
(
'User:
%
s public key auth passed'
%
username
)
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_SUCCESSFUL
else
:
logger
.
warning
(
'User:
%
s public key auth failed'
%
username
)
return
paramiko
.
AUTH_FAILED
return
paramiko
.
AUTH_FAILED
def
get_allowed_auths
(
self
,
username
):
def
get_allowed_auths
(
self
,
username
):
return
'password,publickey'
auth_method_list
=
[]
if
settings
.
CONFIG
.
SSH_PASSWORD_AUTH
:
auth_method_list
.
append
(
'password'
)
if
settings
.
CONFIG
.
SSH_PUBLICK_KEY_AUTH
:
auth_method_list
.
append
(
'publickey'
)
return
','
.
join
(
auth_method_list
)
def
check_channel_shell_request
(
self
,
channel
):
def
check_channel_shell_request
(
self
,
channel
):
self
.
event
.
set
()
self
.
event
.
set
()
...
@@ -100,7 +110,7 @@ class SSHService(paramiko.ServerInterface):
...
@@ -100,7 +110,7 @@ class SSHService(paramiko.ServerInterface):
class
SSHServer
:
class
SSHServer
:
def
__init__
(
self
,
host
,
port
):
def
__init__
(
self
,
host
=
'127.0.0.1'
,
port
=
2200
):
self
.
host
=
host
self
.
host
=
host
self
.
port
=
port
self
.
port
=
port
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
...
@@ -118,58 +128,57 @@ class SSHServer:
...
@@ -118,58 +128,57 @@ class SSHServer:
return
channel
return
channel
def
handle_ssh_request
(
self
,
client
,
addr
):
def
handle_ssh_request
(
self
,
client
,
addr
):
print
(
'Got a connection!'
)
logger
.
info
(
"Get connection from "
+
str
(
addr
)
)
try
:
try
:
t
=
paramiko
.
Transport
(
client
,
gss_kex
=
False
)
t
ransport
=
paramiko
.
Transport
(
client
,
gss_kex
=
False
)
t
.
set_gss_host
(
socket
.
getfqdn
(
""
))
t
ransport
.
set_gss_host
(
socket
.
getfqdn
(
""
))
try
:
try
:
t
.
load_server_moduli
()
t
ransport
.
load_server_moduli
()
except
:
except
:
print
(
'(Failed to load moduli -- gex will be unsupported.)'
)
logger
.
warning
(
'(Failed to load moduli -- gex will be unsupported.)'
)
raise
raise
t
.
add_server_key
(
host_key
)
transport
.
add_server_key
(
SSHService
.
get_host_key
())
service
=
SSHService
()
service
=
SSHService
()
try
:
try
:
t
.
start_server
(
server
=
service
)
t
ransport
.
start_server
(
server
=
service
)
except
paramiko
.
SSHException
:
except
paramiko
.
SSHException
:
print
(
'*** SSH negotiation failed.'
)
print
(
'*** SSH negotiation failed.'
)
return
return
chan
=
t
.
accept
(
20
)
channel
=
transport
.
accept
(
20
)
if
channel
is
None
:
if
chan
is
None
:
print
(
'*** No channel.'
)
print
(
'*** No channel.'
)
return
return
print
(
'Authenticated!'
)
print
(
'Authenticated!'
)
chan
.
settimeout
(
100
)
chan
nel
.
settimeout
(
100
)
chan
.
send
(
'
\r\n\r\n
Welcome to my dorky little BBS!
\r\n\r\n
'
)
chan
nel
.
send
(
'
\r\n\r\n
Welcome to my dorky little BBS!
\r\n\r\n
'
)
chan
.
send
(
'We are on fire all the time! Hooray! Candy corn for everyone!
\r\n
'
)
chan
nel
.
send
(
'We are on fire all the time! Hooray! Candy corn for everyone!
\r\n
'
)
chan
.
send
(
'Happy birthday to Robot Dave!
\r\n\r\n
'
)
chan
nel
.
send
(
'Happy birthday to Robot Dave!
\r\n\r\n
'
)
server_chan
=
self
.
connect
()
server_chan
nel
=
self
.
connect
()
if
not
service
.
event
.
is_set
():
if
not
service
.
event
.
is_set
():
print
(
'*** Client never asked for a shell.'
)
print
(
'*** Client never asked for a shell.'
)
return
return
server_data
=
[]
server_data
=
[]
input_mode
=
True
input_mode
=
True
while
True
:
while
True
:
r
,
w
,
e
=
select
.
select
([
server_chan
,
chan
],
[],
[])
r
,
w
,
e
=
select
.
select
([
server_channel
,
channel
],
[],
[])
if
chan
in
r
:
if
chan
nel
in
r
:
recv_data
=
chan
.
recv
(
1024
)
.
decode
(
'utf8'
)
recv_data
=
chan
nel
.
recv
(
1024
)
.
decode
(
'utf8'
)
# print("From client: " + repr(recv_data))
# print("From client: " + repr(recv_data))
if
len
(
recv_data
)
==
0
:
if
len
(
recv_data
)
==
0
:
break
break
server_chan
.
send
(
recv_data
)
server_chan
nel
.
send
(
recv_data
)
if
server_chan
in
r
:
if
server_chan
nel
in
r
:
recv_data
=
server_chan
.
recv
(
1024
)
.
decode
(
'utf8'
)
recv_data
=
server_chan
nel
.
recv
(
1024
)
.
decode
(
'utf8'
)
# print("From server: " + repr(recv_data))
# print("From server: " + repr(recv_data))
if
len
(
recv_data
)
==
0
:
if
len
(
recv_data
)
==
0
:
break
break
chan
.
send
(
recv_data
)
chan
nel
.
send
(
recv_data
)
if
len
(
recv_data
)
>
20
:
if
len
(
recv_data
)
>
20
:
server_data
.
append
(
'...'
)
server_data
.
append
(
'...'
)
else
:
else
:
...
@@ -190,13 +199,14 @@ class SSHServer:
...
@@ -190,13 +199,14 @@ class SSHServer:
print
(
'*** Caught exception: '
+
str
(
e
.
__class__
)
+
': '
+
str
(
e
))
print
(
'*** Caught exception: '
+
str
(
e
.
__class__
)
+
': '
+
str
(
e
))
traceback
.
print_exc
()
traceback
.
print_exc
()
try
:
try
:
t
.
close
()
t
ransport
.
close
()
except
:
except
:
pass
pass
sys
.
exit
(
1
)
sys
.
exit
(
1
)
def
listen
(
self
):
def
listen
(
self
):
self
.
sock
.
listen
(
5
)
self
.
sock
.
listen
(
5
)
print
(
'Start ssh server
%(host)
s:
%(port)
s'
%
{
'host'
:
self
.
host
,
'port'
:
self
.
port
})
while
True
:
while
True
:
try
:
try
:
client
,
addr
=
self
.
sock
.
accept
()
client
,
addr
=
self
.
sock
.
accept
()
...
@@ -209,7 +219,7 @@ class SSHServer:
...
@@ -209,7 +219,7 @@ class SSHServer:
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
server
=
SSHServer
(
''
,
2200
)
server
=
SSHServer
(
host
=
''
,
port
=
2200
)
try
:
try
:
server
.
listen
()
server
.
listen
()
except
KeyboardInterrupt
:
except
KeyboardInterrupt
:
...
...
apps/users/models.py
View file @
cfef3744
...
@@ -109,6 +109,12 @@ class User(AbstractUser):
...
@@ -109,6 +109,12 @@ class User(AbstractUser):
else
:
else
:
return
True
return
True
@property
def
is_valid
(
self
):
if
self
.
is_active
and
not
self
.
is_expired
:
return
True
return
False
@property
@property
def
private_key
(
self
):
def
private_key
(
self
):
return
decrypt
(
self
.
_private_key
)
return
decrypt
(
self
.
_private_key
)
...
...
apps/users/utils.py
View file @
cfef3744
...
@@ -13,7 +13,8 @@ from django.utils.translation import ugettext as _
...
@@ -13,7 +13,8 @@ from django.utils.translation import ugettext as _
from
paramiko.rsakey
import
RSAKey
from
paramiko.rsakey
import
RSAKey
from
common.tasks
import
send_mail_async
from
common.tasks
import
send_mail_async
from
common.utils
import
reverse
from
common.utils
import
reverse
,
get_object_or_none
from
.models
import
User
try
:
try
:
...
@@ -203,3 +204,20 @@ def validate_ssh_pk(text):
...
@@ -203,3 +204,20 @@ def validate_ssh_pk(text):
return
optionState
(
text
[
1
:])
return
optionState
(
text
[
1
:])
return
startState
([
n
.
strip
()
for
n
in
text
.
splitlines
()])
return
startState
([
n
.
strip
()
for
n
in
text
.
splitlines
()])
def
check_user_is_valid
(
**
kwargs
):
password
=
kwargs
.
pop
(
'password'
,
None
)
public_key
=
kwargs
.
pop
(
'public_key'
,
None
)
user
=
get_object_or_none
(
User
,
**
kwargs
)
if
password
and
not
user
.
check_password
(
password
):
user
=
None
if
public_key
and
not
user
.
public_key
==
public_key
:
user
=
None
if
user
and
user
.
is_valid
:
return
user
return
None
config-example.py
View file @
cfef3744
...
@@ -70,6 +70,10 @@ class Config:
...
@@ -70,6 +70,10 @@ class Config:
# EMAIL_USE_TLS = False # If port is 587, set True
# EMAIL_USE_TLS = False # If port is 587, set True
# EMAIL_SUBJECT_PREFIX = '[Jumpserver] '
# EMAIL_SUBJECT_PREFIX = '[Jumpserver] '
# SSH use password or public key for auth
SSH_PASSWORD_AUTH
=
False
SSH_PUBLIC_KEY_AUTH
=
True
def
__init__
(
self
):
def
__init__
(
self
):
pass
pass
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment