Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IRMA
Github mirrors
irmago
Commits
d4110500
Commit
d4110500
authored
May 10, 2019
by
Sietse Ringers
Browse files
fix: make irma server compatible with GET/POST retries from irmaclient
parent
5999bcfb
Changes
8
Hide whitespace changes
Inline
Side-by-side
internal/servercore/api.go
View file @
d4110500
...
...
@@ -353,6 +353,10 @@ func (s *Server) handleProtocolMessage(
return
}
if
method
==
http
.
MethodGet
{
status
,
output
=
session
.
checkCache
(
message
,
server
.
StatusConnected
)
if
len
(
output
)
!=
0
{
return
}
h
:=
http
.
Header
(
headers
)
min
:=
&
irma
.
ProtocolVersion
{}
max
:=
&
irma
.
ProtocolVersion
{}
...
...
@@ -365,10 +369,12 @@ func (s *Server) handleProtocolMessage(
return
}
status
,
output
=
server
.
JsonResponse
(
session
.
handleGetRequest
(
min
,
max
))
session
.
responseCache
=
responseCache
{
message
:
message
,
response
:
output
,
status
:
status
,
sessionStatus
:
server
.
StatusConnected
}
return
}
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorInvalidRequest
,
""
))
return
default
:
if
noun
==
"statusevents"
{
err
:=
server
.
RemoteError
(
server
.
ErrorInvalidRequest
,
"server sent events not supported by this server"
)
...
...
@@ -388,30 +394,47 @@ func (s *Server) handleProtocolMessage(
}
if
noun
==
"commitments"
&&
session
.
action
==
irma
.
ActionIssuing
{
status
,
output
=
session
.
checkCache
(
message
,
server
.
StatusDone
)
if
len
(
output
)
!=
0
{
return
}
commitments
:=
&
irma
.
IssueCommitmentMessage
{}
if
err
:
=
irma
.
UnmarshalValidate
(
message
,
commitments
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
""
))
if
err
=
irma
.
UnmarshalValidate
(
message
,
commitments
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
err
.
Error
()
))
return
}
status
,
output
=
server
.
JsonResponse
(
session
.
handlePostCommitments
(
commitments
))
session
.
responseCache
=
responseCache
{
message
:
message
,
response
:
output
,
status
:
status
,
sessionStatus
:
server
.
StatusDone
}
return
}
if
noun
==
"proofs"
&&
session
.
action
==
irma
.
ActionDisclosing
{
disclosure
:=
irma
.
Disclosure
{}
if
err
:=
irma
.
UnmarshalValidate
(
message
,
&
disclosure
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
""
))
status
,
output
=
session
.
checkCache
(
message
,
server
.
StatusDone
)
if
len
(
output
)
!=
0
{
return
}
disclosure
:=
&
irma
.
Disclosure
{}
if
err
=
irma
.
UnmarshalValidate
(
message
,
disclosure
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
err
.
Error
()))
return
}
status
,
output
=
server
.
JsonResponse
(
session
.
handlePostDisclosure
(
disclosure
))
session
.
responseCache
=
responseCache
{
message
:
message
,
response
:
output
,
status
:
status
,
sessionStatus
:
server
.
StatusDone
}
return
}
if
noun
==
"proofs"
&&
session
.
action
==
irma
.
ActionSigning
{
status
,
output
=
session
.
checkCache
(
message
,
server
.
StatusDone
)
if
len
(
output
)
!=
0
{
return
}
signature
:=
&
irma
.
SignedMessage
{}
if
err
:
=
irma
.
UnmarshalValidate
(
message
,
signature
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
""
))
if
err
=
irma
.
UnmarshalValidate
(
message
,
signature
);
err
!=
nil
{
status
,
output
=
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorMalformedInput
,
err
.
Error
()
))
return
}
status
,
output
=
server
.
JsonResponse
(
session
.
handlePostSignature
(
signature
))
session
.
responseCache
=
responseCache
{
message
:
message
,
response
:
output
,
status
:
status
,
sessionStatus
:
server
.
StatusDone
}
return
}
...
...
internal/servercore/handle.go
View file @
d4110500
...
...
@@ -82,7 +82,7 @@ func (session *session) handlePostSignature(signature *irma.SignedMessage) (*irm
return
&
session
.
result
.
ProofStatus
,
rerr
}
func
(
session
*
session
)
handlePostDisclosure
(
disclosure
irma
.
Disclosure
)
(
*
irma
.
ProofStatus
,
*
irma
.
RemoteError
)
{
func
(
session
*
session
)
handlePostDisclosure
(
disclosure
*
irma
.
Disclosure
)
(
*
irma
.
ProofStatus
,
*
irma
.
RemoteError
)
{
if
session
.
status
!=
server
.
StatusConnected
{
return
nil
,
server
.
RemoteError
(
server
.
ErrorUnexpectedRequest
,
"Session not yet started or already finished"
)
}
...
...
internal/servercore/helpers.go
View file @
d4110500
package
servercore
import
(
"crypto/sha256"
"encoding/json"
"fmt"
"net/http"
...
...
@@ -47,6 +48,30 @@ func (session *session) fail(err server.Error, message string) *irma.RemoteError
return
rerr
}
const
retryTimeLimit
=
5
*
time
.
Second
// checkCache returns a previously cached response, for replaying against multiple requests from
// irmago's retryablehttp client, if:
// - the same was POSTed as last time
// - last time was not more than 5 seconds ago (retryablehttp client gives up before this)
// - the status is now done (which it should be if this is the second time we receive this message).
func
(
session
*
session
)
checkCache
(
message
[]
byte
,
expectedStatus
server
.
Status
)
(
int
,
[]
byte
)
{
if
len
(
session
.
responseCache
.
response
)
>
0
{
if
session
.
responseCache
.
sessionStatus
!=
expectedStatus
{
// don't replay a cache value that was set in a previous session state
session
.
responseCache
=
responseCache
{}
return
0
,
nil
}
if
sha256
.
Sum256
(
session
.
responseCache
.
message
)
!=
sha256
.
Sum256
(
message
)
||
session
.
lastActive
.
Before
(
time
.
Now
()
.
Add
(
-
retryTimeLimit
))
||
session
.
status
!=
expectedStatus
{
return
server
.
JsonResponse
(
nil
,
session
.
fail
(
server
.
ErrorUnexpectedRequest
,
""
))
}
return
session
.
responseCache
.
status
,
session
.
responseCache
.
response
}
return
0
,
nil
}
// Issuance helpers
func
(
s
*
Server
)
validateIssuanceRequest
(
request
*
irma
.
IssuanceRequest
)
error
{
...
...
internal/servercore/sessions.go
View file @
d4110500
...
...
@@ -24,9 +24,10 @@ type session struct {
request
irma
.
SessionRequest
legacyCompatible
bool
// if the request is convertible to pre-condiscon format
status
server
.
Status
prevStatus
server
.
Status
evtSource
eventsource
.
EventSource
status
server
.
Status
prevStatus
server
.
Status
evtSource
eventsource
.
EventSource
responseCache
responseCache
lastActive
time
.
Time
result
*
server
.
SessionResult
...
...
@@ -37,6 +38,13 @@ type session struct {
sessions
sessionStore
}
type
responseCache
struct
{
message
[]
byte
response
[]
byte
status
int
sessionStatus
server
.
Status
}
type
sessionStore
interface
{
get
(
token
string
)
*
session
clientGet
(
token
string
)
*
session
...
...
internal/sessiontest/handlers_test.go
View file @
d4110500
...
...
@@ -67,6 +67,7 @@ type TestHandler struct {
c
chan
*
SessionResult
client
*
irmaclient
.
Client
expectedServerName
irma
.
TranslatedString
result
string
}
func
(
th
TestHandler
)
KeyshareEnrollmentIncomplete
(
manager
irma
.
SchemeManagerIdentifier
)
{
...
...
@@ -82,7 +83,8 @@ func (th TestHandler) KeyshareEnrollmentDeleted(manager irma.SchemeManagerIdenti
th
.
Failure
(
&
irma
.
SessionError
{
Err
:
errors
.
Errorf
(
"Keyshare enrollment deleted for %s"
,
manager
.
String
())})
}
func
(
th
TestHandler
)
StatusUpdate
(
action
irma
.
Action
,
status
irma
.
Status
)
{}
func
(
th
TestHandler
)
Success
(
result
string
)
{
func
(
th
*
TestHandler
)
Success
(
result
string
)
{
th
.
result
=
result
th
.
c
<-
nil
}
func
(
th
TestHandler
)
Cancelled
()
{
...
...
internal/sessiontest/main_test.go
View file @
d4110500
...
...
@@ -210,7 +210,7 @@ func sessionHelper(t *testing.T, request irma.SessionRequest, sessiontype string
qr
:=
startSession
(
t
,
request
,
sessiontype
)
c
:=
make
(
chan
*
SessionResult
)
h
:=
TestHandler
{
t
,
c
,
client
,
expectedServerName
(
t
,
request
,
client
.
Configuration
)}
h
:=
&
TestHandler
{
t
:
t
,
c
:
c
,
client
:
client
,
expectedServerName
:
expectedServerName
(
t
,
request
,
client
.
Configuration
)}
qrjson
,
err
:=
json
.
Marshal
(
qr
)
require
.
NoError
(
t
,
err
)
client
.
NewSession
(
string
(
qrjson
),
h
)
...
...
internal/sessiontest/requestor_test.go
View file @
d4110500
package
sessiontest
import
(
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"reflect"
"testing"
"github.com/privacybydesign/irmago"
...
...
@@ -15,8 +19,9 @@ import (
type
sessionOption
int
const
(
sessionOptionUpdatedIrmaConfiguration
=
iota
sessionOptionUpdatedIrmaConfiguration
sessionOption
=
1
<<
iota
sessionOptionUnsatisfiableRequest
sessionOptionRetryPost
)
type
requestorSessionResult
struct
{
...
...
@@ -41,12 +46,18 @@ func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *i
})
require
.
NoError
(
t
,
err
)
opts
:=
0
for
_
,
o
:=
range
options
{
opts
|=
int
(
o
)
}
var
h
irmaclient
.
Handler
if
len
(
options
)
==
1
&&
options
[
0
]
==
sessionOptionUnsatisfiableRequest
{
h
=
UnsatisfiableTestHandler
{
TestHandler
{
t
,
clientChan
,
client
,
nil
}}
if
opts
&
int
(
sessionOptionUnsatisfiableRequest
)
>
0
{
h
=
&
UnsatisfiableTestHandler
{
TestHandler
{
t
,
clientChan
,
client
,
nil
,
""
}}
}
else
{
h
=
TestHandler
{
t
,
clientChan
,
client
,
nil
}
h
=
&
TestHandler
{
t
,
clientChan
,
client
,
nil
,
""
}
}
j
,
err
:=
json
.
Marshal
(
qr
)
require
.
NoError
(
t
,
err
)
client
.
NewSession
(
string
(
j
),
h
)
...
...
@@ -55,13 +66,29 @@ func requestorSessionHelper(t *testing.T, request irma.SessionRequest, client *i
require
.
NoError
(
t
,
clientResult
.
Err
)
}
if
len
(
options
)
==
1
&&
options
[
0
]
==
sessionOptionUnsatisfiableRequest
{
if
opts
&
int
(
sessionOptionUnsatisfiableRequest
)
>
0
{
require
.
NotNil
(
t
,
clientResult
)
return
&
requestorSessionResult
{
nil
,
clientResult
.
Missing
}
}
else
{
serverResult
:=
<-
serverChan
require
.
Equal
(
t
,
token
,
serverResult
.
Token
)
return
&
requestorSessionResult
{
serverResult
,
nil
}
}
serverResult
:=
<-
serverChan
require
.
Equal
(
t
,
token
,
serverResult
.
Token
)
if
opts
&
int
(
sessionOptionRetryPost
)
>
0
{
req
,
err
:=
http
.
NewRequest
(
http
.
MethodPost
,
qr
.
URL
+
"/proofs"
,
bytes
.
NewBuffer
([]
byte
(
h
.
(
*
TestHandler
)
.
result
)),
)
require
.
NoError
(
t
,
err
)
req
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
res
,
err
:=
new
(
http
.
Client
)
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
res
.
StatusCode
<
300
)
_
,
err
=
ioutil
.
ReadAll
(
res
.
Body
)
require
.
NoError
(
t
,
err
)
}
return
&
requestorSessionResult
{
serverResult
,
nil
}
}
// Check that nonexistent IRMA identifiers in the session request fail the session
...
...
@@ -75,16 +102,37 @@ func TestRequestorInvalidRequest(t *testing.T) {
require
.
Error
(
t
,
err
)
}
func
TestRequestorDoubleGET
(
t
*
testing
.
T
)
{
StartIrmaServer
(
t
,
false
)
defer
StopIrmaServer
()
qr
,
_
,
err
:=
irmaServer
.
StartSession
(
irma
.
NewDisclosureRequest
(
irma
.
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
),
),
nil
)
require
.
NoError
(
t
,
err
)
// Simulate the first GET by the client in the session protocol, twice
var
o
interface
{}
transport
:=
irma
.
NewHTTPTransport
(
qr
.
URL
)
transport
.
SetHeader
(
irma
.
MinVersionHeader
,
"2.5"
)
transport
.
SetHeader
(
irma
.
MaxVersionHeader
,
"2.5"
)
require
.
NoError
(
t
,
transport
.
Get
(
""
,
&
o
))
require
.
NoError
(
t
,
transport
.
Get
(
""
,
&
o
))
}
func
TestRequestorSignatureSession
(
t
*
testing
.
T
)
{
client
,
_
:=
parseStorage
(
t
)
id
:=
irma
.
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
)
serverResult
:=
requestorSessionHelper
(
t
,
irma
.
NewSignatureRequest
(
"message"
,
id
),
client
)
require
.
Nil
(
t
,
serverResult
.
Err
)
require
.
Equal
(
t
,
irma
.
ProofStatusValid
,
serverResult
.
ProofStatus
)
require
.
NotEmpty
(
t
,
serverResult
.
Disclosed
)
require
.
Equal
(
t
,
id
,
serverResult
.
Disclosed
[
0
][
0
]
.
Identifier
)
require
.
Equal
(
t
,
"456"
,
serverResult
.
Disclosed
[
0
][
0
]
.
Value
[
"en"
])
var
serverResult
*
requestorSessionResult
for
_
,
opt
:=
range
[]
sessionOption
{
0
,
sessionOptionRetryPost
}
{
serverResult
=
requestorSessionHelper
(
t
,
irma
.
NewSignatureRequest
(
"message"
,
id
),
client
,
opt
)
require
.
Nil
(
t
,
serverResult
.
Err
)
require
.
Equal
(
t
,
irma
.
ProofStatusValid
,
serverResult
.
ProofStatus
)
require
.
NotEmpty
(
t
,
serverResult
.
Disclosed
)
require
.
Equal
(
t
,
id
,
serverResult
.
Disclosed
[
0
][
0
]
.
Identifier
)
require
.
Equal
(
t
,
"456"
,
serverResult
.
Disclosed
[
0
][
0
]
.
Value
[
"en"
])
}
// Load the updated scheme in which an attribute was added to the studentCard credential type
schemeid
:=
irma
.
NewSchemeManagerIdentifier
(
"irma-demo"
)
...
...
@@ -102,10 +150,12 @@ func TestRequestorSignatureSession(t *testing.T) {
func
TestRequestorDisclosureSession
(
t
*
testing
.
T
)
{
id
:=
irma
.
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
)
request
:=
irma
.
NewDisclosureRequest
(
id
)
serverResult
:=
testRequestorDisclosure
(
t
,
request
)
require
.
Len
(
t
,
serverResult
.
Disclosed
,
1
)
require
.
Equal
(
t
,
id
,
serverResult
.
Disclosed
[
0
][
0
]
.
Identifier
)
require
.
Equal
(
t
,
"456"
,
serverResult
.
Disclosed
[
0
][
0
]
.
Value
[
"en"
])
for
_
,
opt
:=
range
[]
sessionOption
{
0
,
sessionOptionRetryPost
}
{
serverResult
:=
testRequestorDisclosure
(
t
,
request
,
opt
)
require
.
Len
(
t
,
serverResult
.
Disclosed
,
1
)
require
.
Equal
(
t
,
id
,
serverResult
.
Disclosed
[
0
][
0
]
.
Identifier
)
require
.
Equal
(
t
,
"456"
,
serverResult
.
Disclosed
[
0
][
0
]
.
Value
[
"en"
])
}
}
func
TestRequestorDisclosureMultipleAttrs
(
t
*
testing
.
T
)
{
...
...
@@ -117,8 +167,8 @@ func TestRequestorDisclosureMultipleAttrs(t *testing.T) {
require
.
Len
(
t
,
serverResult
.
Disclosed
,
2
)
}
func
testRequestorDisclosure
(
t
*
testing
.
T
,
request
*
irma
.
DisclosureRequest
)
*
server
.
SessionResult
{
serverResult
:=
requestorSessionHelper
(
t
,
request
,
nil
)
func
testRequestorDisclosure
(
t
*
testing
.
T
,
request
*
irma
.
DisclosureRequest
,
options
...
sessionOption
)
*
server
.
SessionResult
{
serverResult
:=
requestorSessionHelper
(
t
,
request
,
nil
,
options
...
)
require
.
Nil
(
t
,
serverResult
.
Err
)
require
.
Equal
(
t
,
irma
.
ProofStatusValid
,
serverResult
.
ProofStatus
)
return
serverResult
.
SessionResult
...
...
internal/sessiontest/session_test.go
View file @
d4110500
...
...
@@ -366,7 +366,7 @@ func TestDownloadSchemeManager(t *testing.T) {
URL
:
"http://localhost:48681/irma_configuration/irma-demo"
,
})
require
.
NoError
(
t
,
err
)
client
.
NewSession
(
string
(
qr
),
TestHandler
{
t
,
c
,
client
,
nil
})
client
.
NewSession
(
string
(
qr
),
&
TestHandler
{
t
:
t
,
c
:
c
,
client
:
client
,
expectedServerName
:
nil
})
if
result
:=
<-
c
;
result
!=
nil
{
require
.
NoError
(
t
,
result
.
Err
)
}
...
...
@@ -419,7 +419,7 @@ func TestStaticQRSession(t *testing.T) {
c
:=
make
(
chan
*
SessionResult
)
// Perform session
client
.
NewSession
(
string
(
bts
),
TestHandler
{
t
,
c
,
client
,
host
})
client
.
NewSession
(
string
(
bts
),
&
TestHandler
{
t
,
c
,
client
,
host
,
""
})
if
result
:=
<-
c
;
result
!=
nil
{
require
.
NoError
(
t
,
result
.
Err
)
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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