requestor_test.go 9.56 KB
Newer Older
1
2
3
4
package sessiontest

import (
	"encoding/json"
5
	"reflect"
6
7
8
9
	"testing"

	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/test"
10
	"github.com/privacybydesign/irmago/irmaclient"
Sietse Ringers's avatar
Sietse Ringers committed
11
	"github.com/privacybydesign/irmago/server"
12
13
14
	"github.com/stretchr/testify/require"
)

15
type sessionOption int
16

17
18
19
20
21
22
23
24
const (
	sessionOptionUpdatedIrmaConfiguration = iota
	sessionOptionUnsatisfiableRequest
)

type requestorSessionResult struct {
	*server.SessionResult
	Missing irmaclient.MissingAttributes
25
}
26

27
func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *irmaclient.Client, options ...sessionOption) *requestorSessionResult {
28
	if client == nil {
29
		client, _ = parseStorage(t)
30
31
		defer test.ClearTestStorage(t)
	}
32

33
34
35
	StartIrmaServer(t, len(options) == 1 && options[0] == sessionOptionUpdatedIrmaConfiguration)
	defer StopIrmaServer()

36
	clientChan := make(chan *SessionResult)
Sietse Ringers's avatar
Sietse Ringers committed
37
	serverChan := make(chan *server.SessionResult)
38

39
	qr, token, err := irmaServer.StartSession(request, func(result *server.SessionResult) {
40
41
42
43
		serverChan <- result
	})
	require.NoError(t, err)

44
45
46
47
48
49
	var h irmaclient.Handler
	if len(options) == 1 && options[0] == sessionOptionUnsatisfiableRequest {
		h = UnsatisfiableTestHandler{TestHandler{t, clientChan, client, nil}}
	} else {
		h = TestHandler{t, clientChan, client, nil}
	}
50
51
52
53
54
55
56
57
	j, err := json.Marshal(qr)
	require.NoError(t, err)
	client.NewSession(string(j), h)
	clientResult := <-clientChan
	if clientResult != nil {
		require.NoError(t, clientResult.Err)
	}

58
59
60
61
62
63
64
	if len(options) == 1 && options[0] == sessionOptionUnsatisfiableRequest {
		return &requestorSessionResult{nil, clientResult.Missing}
	} else {
		serverResult := <-serverChan
		require.Equal(t, token, serverResult.Token)
		return &requestorSessionResult{serverResult, nil}
	}
65
66
}

67
68
// Check that nonexistent IRMA identifiers in the session request fail the session
func TestRequestorInvalidRequest(t *testing.T) {
69
	StartIrmaServer(t, false)
70
71
72
73
74
75
76
77
	defer StopIrmaServer()
	_, _, err := irmaServer.StartSession(irma.NewDisclosureRequest(
		irma.NewAttributeTypeIdentifier("irma-demo.RU.foo.bar"),
		irma.NewAttributeTypeIdentifier("irma-demo.baz.qux.abc"),
	), nil)
	require.Error(t, err)
}

Sietse Ringers's avatar
Sietse Ringers committed
78
func TestRequestorSignatureSession(t *testing.T) {
79
	client, _ := parseStorage(t)
80
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
81
	serverResult := requestorSessionHelper(t, irma.NewSignatureRequest("message", id), client)
82
83
84
85

	require.Nil(t, serverResult.Err)
	require.Equal(t, irma.ProofStatusValid, serverResult.ProofStatus)
	require.NotEmpty(t, serverResult.Disclosed)
86
87
	require.Equal(t, id, serverResult.Disclosed[0][0].Identifier)
	require.Equal(t, "456", serverResult.Disclosed[0][0].Value["en"])
88
89
90
91
92
93
94
95
96
97
98
99

	// Load the updated scheme in which an attribute was added to the studentCard credential type
	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
	require.NoError(t, client.Configuration.UpdateSchemeManager(schemeid, nil))
	require.NoError(t, client.Configuration.ParseFolder())
	require.Contains(t, client.Configuration.AttributeTypes, irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.newAttribute"))

	// Check that the just created credential is still valid after the new attribute has been added
	_, status, err := serverResult.Signature.Verify(client.Configuration, nil)
	require.NoError(t, err)
	require.Equal(t, irma.ProofStatusValid, status)
100
101
}

Sietse Ringers's avatar
Sietse Ringers committed
102
func TestRequestorDisclosureSession(t *testing.T) {
103
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
104
	request := irma.NewDisclosureRequest(id)
105
106
	serverResult := testRequestorDisclosure(t, request)
	require.Len(t, serverResult.Disclosed, 1)
107
108
	require.Equal(t, id, serverResult.Disclosed[0][0].Identifier)
	require.Equal(t, "456", serverResult.Disclosed[0][0].Value["en"])
109
}
110

111
func TestRequestorDisclosureMultipleAttrs(t *testing.T) {
112
113
114
115
	request := irma.NewDisclosureRequest(
		irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID"),
		irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.level"),
	)
116
117
118
119
120
	serverResult := testRequestorDisclosure(t, request)
	require.Len(t, serverResult.Disclosed, 2)
}

func testRequestorDisclosure(t *testing.T, request *irma.DisclosureRequest) *server.SessionResult {
121
	serverResult := requestorSessionHelper(t, request, nil)
122
123
	require.Nil(t, serverResult.Err)
	require.Equal(t, irma.ProofStatusValid, serverResult.ProofStatus)
124
	return serverResult.SessionResult
125
126
}

Sietse Ringers's avatar
Sietse Ringers committed
127
func TestRequestorIssuanceSession(t *testing.T) {
128
129
130
	testRequestorIssuance(t, false)
}

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
func TestRequestorCombinedSessionMultipleAttributes(t *testing.T) {
	var ir irma.IssuanceRequest
	require.NoError(t, irma.UnmarshalValidate([]byte(`{
		"type":"issuing",
		"credentials": [
			{
				"credential":"irma-demo.MijnOverheid.root",
				"attributes" : {
					"BSN":"12345"
				}
			}
		],
		"disclose" : [
			{
				"label":"Initialen",
				"attributes":["irma-demo.RU.studentCard.studentCardNumber"]
			},
			{
				"label":"Achternaam",
				"attributes" : ["irma-demo.RU.studentCard.studentID"]
			},
			{
				"label":"Geboortedatum",
				"attributes":["irma-demo.RU.studentCard.university"]
			}
		]
	}`), &ir))

159
	require.Equal(t, server.StatusDone, requestorSessionHelper(t, &ir, nil).Status)
160
161
}

162
func testRequestorIssuance(t *testing.T, keyshare bool) {
163
	attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
164
	request := irma.NewIssuanceRequest([]*irma.CredentialRequest{{
165
166
167
168
169
170
171
172
173
174
175
176
		CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard"),
		Attributes: map[string]string{
			"university":        "Radboud",
			"studentCardNumber": "31415927",
			"studentID":         "s1234567",
			"level":             "42",
		},
	}, {
		CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root"),
		Attributes: map[string]string{
			"BSN": "299792458",
		},
177
	}}, attrid)
178
179
180
181
182
183
	if keyshare {
		request.Credentials = append(request.Credentials, &irma.CredentialRequest{
			CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.mijnirma"),
			Attributes:       map[string]string{"email": "testusername"},
		})
	}
184

185
	result := requestorSessionHelper(t, request, nil)
186
187
188
	require.Nil(t, result.Err)
	require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
	require.NotEmpty(t, result.Disclosed)
189
190
191
192
193
	require.Equal(t, attrid, result.Disclosed[0][0].Identifier)
	require.Equal(t, "456", result.Disclosed[0][0].Value["en"])
}

func TestConDisCon(t *testing.T) {
194
	client, _ := parseStorage(t)
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
	ir := getMultipleIssuanceRequest()
	ir.Credentials = append(ir.Credentials, &irma.CredentialRequest{
		Validity:         ir.Credentials[0].Validity,
		CredentialTypeID: irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.fullName"),
		Attributes: map[string]string{
			"firstnames": "Jan Hendrik",
			"firstname":  "Jan",
			"familyname": "Klaassen",
			"prefix":     "van",
		},
	})
	requestorSessionHelper(t, ir, client)

	dr := irma.NewDisclosureRequest()
	dr.Disclose = irma.AttributeConDisCon{
		irma.AttributeDisCon{
			irma.AttributeCon{
				irma.NewAttributeRequest("irma-demo.MijnOverheid.root.BSN"),
				irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.firstname"),
				irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.familyname"),
			},
			irma.AttributeCon{
				irma.NewAttributeRequest("irma-demo.RU.studentCard.studentID"),
				irma.NewAttributeRequest("irma-demo.RU.studentCard.university"),
			},
		},
		//irma.AttributeDisCon{
		//	irma.AttributeCon{
		//		irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.firstname"),
		//		irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.familyname"),
		//	},
		//},
	}

	requestorSessionHelper(t, dr, client)
230
}
231
232

func TestOptionalDisclosure(t *testing.T) {
233
	client, _ := parseStorage(t)
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
	university := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.university")
	studentid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")

	radboud := "Radboud"
	attrs1 := irma.AttributeConDisCon{
		irma.AttributeDisCon{ // Including one non-optional disjunction is required in disclosure and signature sessions
			irma.AttributeCon{irma.AttributeRequest{Type: university}},
		},
		irma.AttributeDisCon{
			irma.AttributeCon{},
			irma.AttributeCon{irma.AttributeRequest{Type: studentid}},
		},
	}
	disclosed1 := [][]*irma.DisclosedAttribute{
		{
			{
250
251
252
253
254
				RawValue:     &radboud,
				Value:        map[string]string{"": radboud, "en": radboud, "nl": radboud},
				Identifier:   irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.university"),
				Status:       irma.AttributeProofStatusPresent,
				IssuanceTime: irma.Timestamp(client.Attributes(university.CredentialTypeIdentifier(), 0).SigningDate()),
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
			},
		},
		{},
	}
	attrs2 := irma.AttributeConDisCon{ // In issuance sessions, it is allowed that all disjunctions are optional
		irma.AttributeDisCon{
			irma.AttributeCon{},
			irma.AttributeCon{irma.AttributeRequest{Type: studentid}},
		},
	}
	disclosed2 := [][]*irma.DisclosedAttribute{{}}

	tests := []struct {
		request   irma.SessionRequest
		attrs     irma.AttributeConDisCon
		disclosed [][]*irma.DisclosedAttribute
	}{
		{irma.NewDisclosureRequest(), attrs1, disclosed1},
		{irma.NewSignatureRequest("message"), attrs1, disclosed1},
		{getIssuanceRequest(true), attrs1, disclosed1},
		{getIssuanceRequest(true), attrs2, disclosed2},
	}

	for _, args := range tests {
		args.request.Disclosure().Disclose = args.attrs

		// TestHandler always prefers the first option when given any choice, so it will not disclose the optional attribute
		result := requestorSessionHelper(t, args.request, client)
		require.True(t, reflect.DeepEqual(args.disclosed, result.Disclosed))
	}
}