This repository has been archived by the owner on May 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
authentication_test.go
198 lines (175 loc) · 5.46 KB
/
authentication_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package test
import (
"context"
"testing"
"time"
wwr "github.com/qbeon/webwire-go"
wwrclt "github.com/qbeon/webwire-go/client"
)
// TestAuthentication verifies the server is connectable,
// and is able to receives requests and signals, create sessions
// and identify clients during request- and signal handling
func TestAuthentication(t *testing.T) {
// Because compareSessions doesn't compare the sessions attached info:
compareSessionInfo := func(actual *wwr.Session) {
info, ok := actual.Info.(struct {
UserID string `json:"uid"`
SomeNumber int `json:"some-number"`
})
if !ok {
t.Errorf("Couldn't cast info from: %v", actual.Info)
}
// Check uid
field := "session.info.UserID"
expectedUID := "clientidentifiergoeshere"
if info.UserID != expectedUID {
t.Errorf("%s differs: %s | %s", field, info.UserID, expectedUID)
return
}
// Check some-number
field = "session.info.some-number"
expectedNumber := int(12345)
if info.SomeNumber != expectedNumber {
t.Errorf("%s differs: %d | %d", field, info.SomeNumber, expectedNumber)
return
}
}
onSessionCreatedHookExecuted := NewPending(1, 1*time.Second, true)
clientSignalReceived := NewPending(1, 1*time.Second, true)
var createdSession *wwr.Session
sessionInfo := struct {
UserID string `json:"uid"`
SomeNumber int `json:"some-number"`
}{
"clientidentifiergoeshere",
12345,
}
expectedCredentials := wwr.Payload{
Encoding: wwr.EncodingUtf8,
Data: []byte("secret_credentials"),
}
expectedConfirmation := wwr.Payload{
Encoding: wwr.EncodingUtf8,
Data: []byte("session_is_correct"),
}
currentStep := 1
// Initialize webwire server
_, addr := setupServer(
t,
wwr.ServerOptions{
SessionsEnabled: true,
Hooks: wwr.Hooks{
OnSignal: func(ctx context.Context) {
defer clientSignalReceived.Done()
// Extract request message and requesting client from the context
msg := ctx.Value(wwr.Msg).(wwr.Message)
compareSessions(t, createdSession, msg.Client.Session)
compareSessionInfo(msg.Client.Session)
},
OnRequest: func(ctx context.Context) (wwr.Payload, error) {
// Extract request message and requesting client from the context
msg := ctx.Value(wwr.Msg).(wwr.Message)
// If already authenticated then check session
if currentStep > 1 {
compareSessions(t, createdSession, msg.Client.Session)
compareSessionInfo(msg.Client.Session)
return expectedConfirmation, nil
}
// Try to create a new session
if err := msg.Client.CreateSession(sessionInfo); err != nil {
return wwr.Payload{}, err
}
// Authentication step is passed
currentStep = 2
// Return the key of the newly created session (use default binary encoding)
return wwr.Payload{
Data: []byte(msg.Client.Session.Key),
}, nil
},
// Define dummy hooks to enable sessions on this server
OnSessionCreated: func(_ *wwr.Client) error { return nil },
OnSessionLookup: func(_ string) (*wwr.Session, error) { return nil, nil },
OnSessionClosed: func(_ *wwr.Client) error { return nil },
},
},
)
// Initialize client
client := wwrclt.NewClient(
addr,
wwrclt.Options{
Hooks: wwrclt.Hooks{
OnSessionCreated: func(session *wwr.Session) {
// The session info object won't be of initial structure type
// because of intermediate JSON encoding
// it'll be a map of arbitrary values with string keys
info := session.Info.(map[string]interface{})
// Check uid
field := "session.info.uid"
expectedUID := "clientidentifiergoeshere"
actualUID, ok := info["uid"].(string)
if !ok {
t.Errorf("expected %s not string", field)
return
}
if actualUID != expectedUID {
t.Errorf("%s differs: %s | %s", field, actualUID, expectedUID)
return
}
// Check some-number
field = "session.info.some-number"
expectedNumber := float64(12345)
actualNumber, ok := info["some-number"].(float64)
if !ok {
t.Errorf("expected %s not float64", field)
return
}
if actualNumber != expectedNumber {
t.Errorf("%s differs: %f | %f", field, actualNumber, expectedNumber)
return
}
onSessionCreatedHookExecuted.Done()
},
},
DefaultRequestTimeout: 2 * time.Second,
},
)
defer client.Close()
if err := client.Connect(); err != nil {
t.Fatalf("Couldn't connect: %s", err)
}
// Send authentication request and await reply
authReqReply, err := client.Request("login", expectedCredentials)
if err != nil {
t.Fatalf("Request failed: %s", err)
}
tmp := client.Session()
createdSession = &tmp
// Verify reply
comparePayload(
t,
"authentication reply",
wwr.Payload{
Data: []byte(createdSession.Key),
},
authReqReply,
)
// Send a test-request to verify the session on the server
// and await response
testReqReply, err := client.Request("test", expectedCredentials)
if err != nil {
t.Fatalf("Request failed: %s", err)
}
// Verify reply
comparePayload(t, "test reply", expectedConfirmation, testReqReply)
// Send a test-signal to verify the session on the server
if err := client.Signal("test", expectedCredentials); err != nil {
t.Fatalf("Request failed: %s", err)
}
if err := clientSignalReceived.Wait(); err != nil {
t.Fatal("Client signal not received")
}
// Expect the session creation hook to be executed in the client
if err := onSessionCreatedHookExecuted.Wait(); err != nil {
t.Fatalf("client.OnSessionCreated hook wasn't executed")
}
}