Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
webssh
Overview
Overview
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
郑天保
webssh
Commits
d6de1340
Commit
d6de1340
authored
Aug 18, 2018
by
Sheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added max_body_size for limiting the size of post form
parent
d38453fd
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
144 additions
and
5 deletions
+144
-5
sshserver.py
tests/sshserver.py
+2
-1
test_app.py
tests/test_app.py
+86
-2
user_rsa_key
tests/user_rsa_key
+15
-0
utils.py
tests/utils.py
+38
-0
main.py
webssh/main.py
+2
-2
settings.py
webssh/settings.py
+1
-0
No files found.
tests/sshserver.py
View file @
d6de1340
...
...
@@ -64,12 +64,13 @@ class Server(paramiko.ServerInterface):
return
paramiko
.
OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
def
check_auth_password
(
self
,
username
,
password
):
print
(
'Auth attempt with username: {!r} & password: {!r}'
.
format
(
username
,
password
))
# noqa
if
(
username
in
[
'robey'
,
'bar'
])
and
(
password
==
'foo'
):
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_FAILED
def
check_auth_publickey
(
self
,
username
,
key
):
print
(
'Auth attempt with
key: '
+
u
(
hexlify
(
key
.
get_fingerprint
())))
print
(
'Auth attempt with
username: {!r} & key: {!r}'
.
format
(
username
,
u
(
hexlify
(
key
.
get_fingerprint
()))))
# noqa
if
(
username
==
'robey'
)
and
(
key
==
self
.
good_pub_key
):
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_FAILED
...
...
tests/test_app.py
View file @
d6de1340
import
json
import
webssh.handler
as
handler
import
random
import
threading
import
tornado.websocket
import
tornado.gen
import
webssh.handler
as
handler
from
tornado.testing
import
AsyncHTTPTestCase
from
tornado.httpclient
import
HTTPError
from
tornado.options
import
options
from
webssh.main
import
make_app
,
make_handlers
from
webssh.settings
import
get_app_settings
from
webssh.settings
import
get_app_settings
,
max_body_size
from
tests.sshserver
import
run_ssh_server
,
banner
from
tests.utils
import
encode_multipart_formdata
handler
.
DELAY
=
0.1
...
...
@@ -20,6 +22,12 @@ class TestApp(AsyncHTTPTestCase):
running
=
[
True
]
sshserver_port
=
2200
body
=
u'hostname=127.0.0.1&port={}&username=robey&password=foo'
.
format
(
sshserver_port
)
# noqa
body_dict
=
{
'hostname'
:
'127.0.0.1'
,
'port'
:
str
(
sshserver_port
),
'username'
:
'robey'
,
'password'
:
''
}
def
get_app
(
self
):
loop
=
self
.
io_loop
...
...
@@ -44,6 +52,14 @@ class TestApp(AsyncHTTPTestCase):
cls
.
running
.
pop
()
print
(
'='
*
20
)
def
read_privatekey
(
self
,
filename
):
return
open
(
filename
,
'rb'
)
.
read
()
.
decode
(
'utf-8'
)
def
get_httpserver_options
(
self
):
options
=
super
(
TestApp
,
self
)
.
get_httpserver_options
()
options
.
update
(
max_body_size
=
max_body_size
)
return
options
def
test_app_with_invalid_form
(
self
):
response
=
self
.
fetch
(
'/'
)
self
.
assertEqual
(
response
.
code
,
200
)
...
...
@@ -104,6 +120,74 @@ class TestApp(AsyncHTTPTestCase):
ws
.
close
()
@tornado.testing.gen_test
def
test_app_auth_with_valid_pubkey_for_user_robey
(
self
):
url
=
self
.
get_url
(
'/'
)
client
=
self
.
get_http_client
()
response
=
yield
client
.
fetch
(
url
)
self
.
assertEqual
(
response
.
code
,
200
)
privatekey
=
self
.
read_privatekey
(
'tests/user_rsa_key'
)
files
=
[(
'privatekey'
,
'user_rsa_key'
,
privatekey
)]
content_type
,
body
=
encode_multipart_formdata
(
self
.
body_dict
.
items
(),
files
)
headers
=
{
"Content-Type"
:
content_type
,
'content-length'
:
str
(
len
(
body
))
}
response
=
yield
client
.
fetch
(
url
,
method
=
"POST"
,
headers
=
headers
,
body
=
body
)
data
=
json
.
loads
(
response
.
body
.
decode
(
'utf-8'
))
self
.
assertIsNone
(
data
[
'status'
])
self
.
assertIsNotNone
(
data
[
'id'
])
self
.
assertIsNotNone
(
data
[
'encoding'
])
url
=
url
.
replace
(
'http'
,
'ws'
)
ws_url
=
url
+
'ws?id='
+
data
[
'id'
]
ws
=
yield
tornado
.
websocket
.
websocket_connect
(
ws_url
)
msg
=
yield
ws
.
read_message
()
self
.
assertEqual
(
msg
.
decode
(
data
[
'encoding'
]),
banner
)
ws
.
close
()
@tornado.testing.gen_test
def
test_app_auth_with_invalid_pubkey_for_user_robey
(
self
):
url
=
self
.
get_url
(
'/'
)
client
=
self
.
get_http_client
()
response
=
yield
client
.
fetch
(
url
)
self
.
assertEqual
(
response
.
code
,
200
)
privatekey
=
self
.
read_privatekey
(
'tests/user_rsa_key'
)
privatekey
=
privatekey
[:
100
]
+
u'bad'
+
privatekey
[
100
:]
files
=
[(
'privatekey'
,
'user_rsa_key'
,
privatekey
)]
content_type
,
body
=
encode_multipart_formdata
(
self
.
body_dict
.
items
(),
files
)
headers
=
{
"Content-Type"
:
content_type
,
'content-length'
:
str
(
len
(
body
))
}
response
=
yield
client
.
fetch
(
url
,
method
=
"POST"
,
headers
=
headers
,
body
=
body
)
data
=
json
.
loads
(
response
.
body
.
decode
(
'utf-8'
))
self
.
assertIsNotNone
(
data
[
'status'
])
self
.
assertIsNone
(
data
[
'id'
])
self
.
assertIsNone
(
data
[
'encoding'
])
@tornado.testing.gen_test
def
test_app_post_form_with_large_body_size
(
self
):
url
=
self
.
get_url
(
'/'
)
client
=
self
.
get_http_client
()
response
=
yield
client
.
fetch
(
url
)
self
.
assertEqual
(
response
.
code
,
200
)
privatekey
=
u'h'
*
(
2
*
max_body_size
)
files
=
[(
'privatekey'
,
'user_rsa_key'
,
privatekey
)]
content_type
,
body
=
encode_multipart_formdata
(
self
.
body_dict
.
items
(),
files
)
headers
=
{
"Content-Type"
:
content_type
,
'content-length'
:
str
(
len
(
body
))
}
with
self
.
assertRaises
(
HTTPError
):
yield
client
.
fetch
(
url
,
method
=
"POST"
,
headers
=
headers
,
body
=
body
)
@tornado.testing.gen_test
def
test_app_with_correct_credentials_user_robey
(
self
):
url
=
self
.
get_url
(
'/'
)
client
=
self
.
get_http_client
()
...
...
tests/user_rsa_key
0 → 100644
View file @
d6de1340
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDI7iK3d8eWYZlYloat94c5VjtFY7c/0zuGl8C7uMnZ3t6i2G99
66hEW0nCFSZkOW5F0XKEVj+EUCHvo8koYC6wiohAqWQnEwIoOoh7GSAcB8gP/qaq
+adIl/Rvlby/mHakj+y05LBND6nFWHAn1y1gOFFKUXSJNRZPXSFy47gqzwIBIwKB
gQCbANjz7q/pCXZLp1Hz6tYHqOvlEmjK1iabB1oqafrMpJ0eibUX/u+FMHq6StR5
M5413BaDWHokPdEJUnabfWXXR3SMlBUKrck0eAer1O8m78yxu3OEdpRk+znVo4DL
guMeCdJB/qcF0kEsx+Q8HP42MZU1oCmk3PbfXNFwaHbWuwJBAOQ/ry/hLD7AqB8x
DmCM82A9E59ICNNlHOhxpJoh6nrNTPCsBAEu/SmqrL8mS6gmbRKUaya5Lx1pkxj2
s/kWOokCQQDhXCcYXjjWiIfxhl6Rlgkk1vmI0l6785XSJNv4P7pXjGmShXfIzroh
S8uWK3tL0GELY7+UAKDTUEVjjQdGxYSXAkEA3bo1JzKCwJ3lJZ1ebGuqmADRO6UP
40xH977aadfN1mEI6cusHmgpISl0nG5YH7BMsvaT+bs1FUH8m+hXDzoqOwJBAK3Z
X/za+KV/REya2z0b+GzgWhkXUGUa/owrEBdHGriQ47osclkUgPUdNqcLmaDilAF4
1Z4PHPrI5RJIONAx+JECQQC/fChqjBgFpk6iJ+BOdSexQpgfxH/u/457W10Y43HR
soS+8btbHqjQkowQ/2NTlUfWvqIlfxs6ZbFsIp/HrhZL
-----END RSA PRIVATE KEY-----
tests/utils.py
0 → 100644
View file @
d6de1340
import
mimetypes
from
uuid
import
uuid4
def
encode_multipart_formdata
(
fields
,
files
):
"""
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be
uploaded as files.
Return (content_type, body) ready for httplib.HTTP instance
"""
boundary
=
uuid4
()
.
hex
CRLF
=
'
\r\n
'
L
=
[]
for
(
key
,
value
)
in
fields
:
L
.
append
(
'--'
+
boundary
)
L
.
append
(
'Content-Disposition: form-data; name="
%
s"'
%
key
)
L
.
append
(
''
)
L
.
append
(
value
)
for
(
key
,
filename
,
value
)
in
files
:
L
.
append
(
'--'
+
boundary
)
L
.
append
(
'Content-Disposition: form-data; name="
%
s"; filename="
%
s"'
%
(
key
,
filename
)
)
L
.
append
(
'Content-Type:
%
s'
%
get_content_type
(
filename
))
L
.
append
(
''
)
L
.
append
(
value
)
L
.
append
(
'--'
+
boundary
+
'--'
)
L
.
append
(
''
)
body
=
CRLF
.
join
(
L
)
content_type
=
'multipart/form-data; boundary=
%
s'
%
boundary
return
content_type
,
body
def
get_content_type
(
filename
):
return
mimetypes
.
guess_type
(
filename
)[
0
]
or
'application/octet-stream'
webssh/main.py
View file @
d6de1340
...
...
@@ -5,7 +5,7 @@ import tornado.ioloop
from
tornado.options
import
parse_command_line
,
options
from
webssh.handler
import
IndexHandler
,
WsockHandler
from
webssh.settings
import
(
get_app_settings
,
get_host_keys_settings
,
get_policy_setting
)
get_policy_setting
,
max_body_size
)
def
make_handlers
(
loop
,
options
):
...
...
@@ -29,7 +29,7 @@ def main():
parse_command_line
()
loop
=
tornado
.
ioloop
.
IOLoop
.
current
()
app
=
make_app
(
make_handlers
(
loop
,
options
),
get_app_settings
(
options
))
app
.
listen
(
options
.
port
,
options
.
address
)
app
.
listen
(
options
.
port
,
options
.
address
,
max_body_size
=
max_body_size
)
logging
.
info
(
'Listening on {}:{}'
.
format
(
options
.
address
,
options
.
port
))
loop
.
start
()
...
...
webssh/settings.py
View file @
d6de1340
...
...
@@ -29,6 +29,7 @@ define('version', type=bool, help='Show version information',
base_dir
=
os
.
path
.
dirname
(
__file__
)
max_body_size
=
1
*
1024
*
1024
def
get_app_settings
(
options
):
...
...
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