Skip to content

Commit

Permalink
Merge pull request #46 from evanlinjin/feature/hypervisor-session-#18
Browse files Browse the repository at this point in the history
Invalidate Hypervisor session after password change.
  • Loading branch information
jdknives authored Nov 7, 2019
2 parents 874aaad + 43bbce1 commit f6f0681
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 62 deletions.
2 changes: 2 additions & 0 deletions cmd/skywire-visor/commands/root.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package commands

// NOTE: "net/http/pprof" is used for profiling.
import (
"bufio"
"context"
Expand All @@ -10,6 +11,7 @@ import (
"log"
"log/syslog"
"net/http"
_ "net/http/pprof" //nolint:gosec
"os"
"os/signal"
"path/filepath"
Expand Down
144 changes: 82 additions & 62 deletions pkg/hypervisor/hypervisor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,25 @@ func TestNewNode(t *testing.T) {
}

type TestCase struct {
Method string
URI string
Body io.Reader
ReqMethod string
ReqURI string
ReqBody io.Reader
ReqMod func(req *http.Request)
RespStatus int
RespBody func(t *testing.T, resp *http.Response)
}

testCases := func(t *testing.T, addr string, client *http.Client, cases []TestCase) {
for i, tc := range cases {
testTag := fmt.Sprintf("[%d] %s", i, tc.URI)
testTag := fmt.Sprintf("[%d] %s", i, tc.ReqURI)

req, err := http.NewRequest(tc.Method, "https://"+addr+tc.URI, tc.Body)
req, err := http.NewRequest(tc.ReqMethod, "https://"+addr+tc.ReqURI, tc.ReqBody)
require.NoError(t, err, testTag)

if tc.ReqMod != nil {
tc.ReqMod(req)
}

resp, err := client.Do(req)
require.NoError(t, err, testTag)

Expand All @@ -99,9 +104,9 @@ func TestNewNode(t *testing.T) {

makeCase := func(method string, uri string, body io.Reader) TestCase {
return TestCase{
Method: method,
URI: uri,
Body: body,
ReqMethod: method,
ReqURI: uri,
ReqBody: body,
RespStatus: http.StatusUnauthorized,
RespBody: func(t *testing.T, r *http.Response) {
body, err := decodeErrorBody(r.Body)
Expand All @@ -124,9 +129,9 @@ func TestNewNode(t *testing.T) {

testCases(t, addr, client, []TestCase{
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"invalid_user","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"invalid_user","password":"Secure1234"}`),
RespStatus: http.StatusForbidden,
RespBody: func(t *testing.T, r *http.Response) {
body, err := decodeErrorBody(r.Body)
Expand All @@ -135,9 +140,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -154,9 +159,9 @@ func TestNewNode(t *testing.T) {

testCases(t, addr, client, []TestCase{
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -165,9 +170,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -176,9 +181,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusForbidden,
RespBody: func(t *testing.T, r *http.Response) {
body, err := decodeErrorBody(r.Body)
Expand All @@ -195,9 +200,9 @@ func TestNewNode(t *testing.T) {

testCases(t, addr, client, []TestCase{
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -206,9 +211,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -217,13 +222,13 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodGet,
URI: "/api/user",
ReqMethod: http.MethodGet,
ReqURI: "/api/user",
RespStatus: http.StatusOK,
},
{
Method: http.MethodGet,
URI: "/api/nodes",
ReqMethod: http.MethodGet,
ReqURI: "/api/nodes",
RespStatus: http.StatusOK,
},
})
Expand All @@ -235,9 +240,9 @@ func TestNewNode(t *testing.T) {

testCases(t, addr, client, []TestCase{
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -246,9 +251,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -257,8 +262,8 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/logout",
ReqMethod: http.MethodPost,
ReqURI: "/api/logout",
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -267,8 +272,8 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodGet,
URI: "/api/user",
ReqMethod: http.MethodGet,
ReqURI: "/api/user",
RespStatus: http.StatusUnauthorized,
RespBody: func(t *testing.T, r *http.Response) {
body, err := decodeErrorBody(r.Body)
Expand All @@ -277,8 +282,8 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodGet,
URI: "/api/nodes",
ReqMethod: http.MethodGet,
ReqURI: "/api/nodes",
RespStatus: http.StatusUnauthorized,
RespBody: func(t *testing.T, r *http.Response) {
body, err := decodeErrorBody(r.Body)
Expand All @@ -293,18 +298,22 @@ func TestNewNode(t *testing.T) {
// - Create account.
// - Login.
// - Change Password.
// - Attempt action (should fail).
// - Logout.
// - Login with old password (should fail).
// - Login with new password (should succeed).

addr, client, stop := startNode(defaultMockConfig())
defer stop()

// To emulate an active session.
var cookies []*http.Cookie

testCases(t, addr, client, []TestCase{
{
Method: http.MethodPost,
URI: "/api/create-account",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/create-account",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -313,20 +322,21 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
cookies = r.Cookies()
var ok bool
assert.NoError(t, json.NewDecoder(r.Body).Decode(&ok))
assert.True(t, ok)
},
},
{
Method: http.MethodPost,
URI: "/api/change-password",
Body: strings.NewReader(`{"old_password":"Secure1234","new_password":"NewSecure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/change-password",
ReqBody: strings.NewReader(`{"old_password":"Secure1234","new_password":"NewSecure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -335,8 +345,18 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/logout",
ReqMethod: http.MethodGet,
ReqURI: "/api/nodes",
ReqMod: func(req *http.Request) {
for _, cookie := range cookies {
req.AddCookie(cookie)
}
},
RespStatus: http.StatusUnauthorized,
},
{
ReqMethod: http.MethodPost,
ReqURI: "/api/logout",
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand All @@ -345,9 +365,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"Secure1234"}`),
RespStatus: http.StatusUnauthorized,
RespBody: func(t *testing.T, r *http.Response) {
b, err := decodeErrorBody(r.Body)
Expand All @@ -356,9 +376,9 @@ func TestNewNode(t *testing.T) {
},
},
{
Method: http.MethodPost,
URI: "/api/login",
Body: strings.NewReader(`{"username":"admin","password":"NewSecure1234"}`),
ReqMethod: http.MethodPost,
ReqURI: "/api/login",
ReqBody: strings.NewReader(`{"username":"admin","password":"NewSecure1234"}`),
RespStatus: http.StatusOK,
RespBody: func(t *testing.T, r *http.Response) {
var ok bool
Expand Down
11 changes: 11 additions & 0 deletions pkg/hypervisor/user_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (s *UserManager) ChangePassword() http.HandlerFunc {
httputil.WriteJSON(w, r, http.StatusForbidden, ErrUserNotFound)
return
}
s.delAllSessionsOfUser(user.Name)
httputil.WriteJSON(w, r, http.StatusOK, true)
}
}
Expand Down Expand Up @@ -245,6 +246,16 @@ func (s *UserManager) delSession(w http.ResponseWriter, r *http.Request) error {
return nil
}

func (s *UserManager) delAllSessionsOfUser(userName string) {
s.mu.Lock()
for sid, session := range s.sessions {
if session.User == userName {
delete(s.sessions, sid)
}
}
s.mu.Unlock()
}

func (s *UserManager) session(r *http.Request) (User, Session, bool) {
cookie, err := r.Cookie(sessionCookieName)
if err != nil {
Expand Down

0 comments on commit f6f0681

Please sign in to comment.