Commit e995284f authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Add support for posting session result to callback url

parent c4860832
......@@ -219,14 +219,12 @@ func HandleProtocolMessage(
session.Lock()
defer session.Unlock()
// However we return, if the session has been finished or cancelled by any of the handlers
// then we should inform the user by returning a SessionResult - but only if we have not
// already done this in the past, e.g. by a previous HTTP call handled by this function
// However we return, if the session status has been updated
// then we should inform the user by returning a SessionResult
defer func() {
if session.status.Finished() && !session.returned {
session.returned = true
if session.status != session.prevStatus {
session.prevStatus = session.status
result = session.result
conf.Logger.Infof("Session %s done, status %s", session.token, session.result.Status)
}
}()
......
......@@ -19,7 +19,7 @@ func (session *session) handleDelete() {
}
session.markAlive()
session.result = &server.SessionResult{Token: session.token, Status: server.StatusCancelled}
session.result = &server.SessionResult{Token: session.token, Status: server.StatusCancelled, Type: session.action}
session.setStatus(server.StatusCancelled)
}
......
......@@ -22,7 +22,7 @@ func (session *session) markAlive() {
}
func (session *session) setStatus(status server.Status) {
conf.Logger.Debugf("Status of session %s updated to %s", session.token, status)
conf.Logger.Debugf("Status of session %s updated from %s to %s", session.token, session.status, status)
session.status = status
session.result.Status = status
sessions.update(session)
......
......@@ -22,11 +22,11 @@ type session struct {
rrequest irma.RequestorRequest
request irma.SessionRequest
status server.Status
evtSource eventsource.EventSource
status server.Status
prevStatus server.Status
evtSource eventsource.EventSource
lastActive time.Time
returned bool
result *server.SessionResult
kssProofs map[irma.SchemeManagerIdentifier]*gabi.ProofP
......@@ -133,6 +133,7 @@ func newSession(action irma.Action, request irma.RequestorRequest) *session {
lastActive: time.Now(),
token: token,
status: server.StatusInitialized,
prevStatus: server.StatusInitialized,
result: &server.SessionResult{
Token: token,
Type: action,
......
......@@ -90,8 +90,8 @@ func HttpHandlerFunc() http.HandlerFunc {
if err != nil {
_ = server.LogError(errors.WrapPrefix(err, "http.ResponseWriter.Write() returned error", 0))
}
if result != nil {
if handler, ok := handlers[result.Token]; ok {
if result != nil && result.Status.Finished() {
if handler := handlers[result.Token]; handler != nil {
go handler(result)
}
}
......
......@@ -14,6 +14,7 @@ import (
"github.com/dgrijalva/jwt-go"
"github.com/go-chi/chi"
"github.com/go-chi/cors"
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server"
"github.com/privacybydesign/irmago/server/irmarequestor"
......@@ -204,9 +205,14 @@ func handleCreate(w http.ResponseWriter, r *http.Request) {
return
}
}
if rrequest.Base().CallbackUrl != "" && conf.jwtPrivateKey == nil {
conf.Logger.Warn("Requestor %s provided callbackUrl but no JWT private key is installed")
server.WriteError(w, server.ErrorUnsupported, "")
return
}
// Everything is authenticated and parsed, we're good to go!
qr, _, err := irmarequestor.StartSession(rrequest, nil)
qr, _, err := irmarequestor.StartSession(rrequest, doResultCallback)
if err != nil {
server.WriteError(w, server.ErrorInvalidRequest, err.Error())
return
......@@ -262,30 +268,14 @@ func handleJwtResult(w http.ResponseWriter, r *http.Request) {
return
}
claims := struct {
jwt.StandardClaims
*server.SessionResult
}{
SessionResult: res,
}
claims.Issuer = conf.JwtIssuer
claims.IssuedAt = time.Now().Unix()
claims.Subject = string(res.Type) + "_result"
validity := irmarequestor.GetRequest(sessiontoken).Base().ResultJwtValidity
if validity != 0 {
claims.ExpiresAt = time.Now().Unix() + int64(validity)
}
// Sign the jwt and return it
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
resultJwt, err := token.SignedString(conf.jwtPrivateKey)
j, err := resultJwt(res)
if err != nil {
conf.Logger.Error("Failed to sign session result JWT")
_ = server.LogError(err)
server.WriteError(w, server.ErrorUnknown, err.Error())
return
}
server.WriteString(w, resultJwt)
server.WriteString(w, j)
}
func handleJwtProofs(w http.ResponseWriter, r *http.Request) {
......@@ -365,3 +355,45 @@ func handlePublicKey(w http.ResponseWriter, r *http.Request) {
})
_, _ = w.Write(pubBytes)
}
func resultJwt(sessionresult *server.SessionResult) (string, error) {
claims := struct {
jwt.StandardClaims
*server.SessionResult
}{
StandardClaims: jwt.StandardClaims{
Issuer: conf.JwtIssuer,
IssuedAt: time.Now().Unix(),
Subject: string(sessionresult.Type) + "_result",
},
SessionResult: sessionresult,
}
validity := irmarequestor.GetRequest(sessionresult.Token).Base().ResultJwtValidity
if validity != 0 {
claims.ExpiresAt = time.Now().Unix() + int64(validity)
}
// Sign the jwt and return it
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
return token.SignedString(conf.jwtPrivateKey)
}
func doResultCallback(result *server.SessionResult) {
callbackUrl := irmarequestor.GetRequest(result.Token).Base().CallbackUrl
if callbackUrl == "" || conf.jwtPrivateKey == nil {
return
}
conf.Logger.Debug("POSTing session result to ", callbackUrl)
j, err := resultJwt(result)
if err != nil {
_ = server.LogError(errors.WrapPrefix(err, "Failed to create JWT for result callback", 0))
return
}
var x string // dummy for the server's return value that we don't care about
if err := irma.NewHTTPTransport(callbackUrl).Post("", &x, j); err != nil {
// not our problem, log it and go on
conf.Logger.Warn(errors.WrapPrefix(err, "Failed to POST session result to callback URL", 0))
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment