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( ...@@ -219,14 +219,12 @@ func HandleProtocolMessage(
session.Lock() session.Lock()
defer session.Unlock() defer session.Unlock()
// However we return, if the session has been finished or cancelled by any of the handlers // However we return, if the session status has been updated
// then we should inform the user by returning a SessionResult - but only if we have not // then we should inform the user by returning a SessionResult
// already done this in the past, e.g. by a previous HTTP call handled by this function
defer func() { defer func() {
if session.status.Finished() && !session.returned { if session.status != session.prevStatus {
session.returned = true session.prevStatus = session.status
result = session.result result = session.result
conf.Logger.Infof("Session %s done, status %s", session.token, session.result.Status)
} }
}() }()
......
...@@ -19,7 +19,7 @@ func (session *session) handleDelete() { ...@@ -19,7 +19,7 @@ func (session *session) handleDelete() {
} }
session.markAlive() 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) session.setStatus(server.StatusCancelled)
} }
......
...@@ -22,7 +22,7 @@ func (session *session) markAlive() { ...@@ -22,7 +22,7 @@ func (session *session) markAlive() {
} }
func (session *session) setStatus(status server.Status) { 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.status = status
session.result.Status = status session.result.Status = status
sessions.update(session) sessions.update(session)
......
...@@ -22,11 +22,11 @@ type session struct { ...@@ -22,11 +22,11 @@ type session struct {
rrequest irma.RequestorRequest rrequest irma.RequestorRequest
request irma.SessionRequest request irma.SessionRequest
status server.Status status server.Status
evtSource eventsource.EventSource prevStatus server.Status
evtSource eventsource.EventSource
lastActive time.Time lastActive time.Time
returned bool
result *server.SessionResult result *server.SessionResult
kssProofs map[irma.SchemeManagerIdentifier]*gabi.ProofP kssProofs map[irma.SchemeManagerIdentifier]*gabi.ProofP
...@@ -133,6 +133,7 @@ func newSession(action irma.Action, request irma.RequestorRequest) *session { ...@@ -133,6 +133,7 @@ func newSession(action irma.Action, request irma.RequestorRequest) *session {
lastActive: time.Now(), lastActive: time.Now(),
token: token, token: token,
status: server.StatusInitialized, status: server.StatusInitialized,
prevStatus: server.StatusInitialized,
result: &server.SessionResult{ result: &server.SessionResult{
Token: token, Token: token,
Type: action, Type: action,
......
...@@ -90,8 +90,8 @@ func HttpHandlerFunc() http.HandlerFunc { ...@@ -90,8 +90,8 @@ func HttpHandlerFunc() http.HandlerFunc {
if err != nil { if err != nil {
_ = server.LogError(errors.WrapPrefix(err, "http.ResponseWriter.Write() returned error", 0)) _ = server.LogError(errors.WrapPrefix(err, "http.ResponseWriter.Write() returned error", 0))
} }
if result != nil { if result != nil && result.Status.Finished() {
if handler, ok := handlers[result.Token]; ok { if handler := handlers[result.Token]; handler != nil {
go handler(result) go handler(result)
} }
} }
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/go-chi/cors" "github.com/go-chi/cors"
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server" "github.com/privacybydesign/irmago/server"
"github.com/privacybydesign/irmago/server/irmarequestor" "github.com/privacybydesign/irmago/server/irmarequestor"
...@@ -204,9 +205,14 @@ func handleCreate(w http.ResponseWriter, r *http.Request) { ...@@ -204,9 +205,14 @@ func handleCreate(w http.ResponseWriter, r *http.Request) {
return 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! // 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 { if err != nil {
server.WriteError(w, server.ErrorInvalidRequest, err.Error()) server.WriteError(w, server.ErrorInvalidRequest, err.Error())
return return
...@@ -262,30 +268,14 @@ func handleJwtResult(w http.ResponseWriter, r *http.Request) { ...@@ -262,30 +268,14 @@ func handleJwtResult(w http.ResponseWriter, r *http.Request) {
return return
} }
claims := struct { j, err := resultJwt(res)
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)
if err != nil { if err != nil {
conf.Logger.Error("Failed to sign session result JWT") conf.Logger.Error("Failed to sign session result JWT")
_ = server.LogError(err) _ = server.LogError(err)
server.WriteError(w, server.ErrorUnknown, err.Error()) server.WriteError(w, server.ErrorUnknown, err.Error())
return return
} }
server.WriteString(w, resultJwt) server.WriteString(w, j)
} }
func handleJwtProofs(w http.ResponseWriter, r *http.Request) { func handleJwtProofs(w http.ResponseWriter, r *http.Request) {
...@@ -365,3 +355,45 @@ func handlePublicKey(w http.ResponseWriter, r *http.Request) { ...@@ -365,3 +355,45 @@ func handlePublicKey(w http.ResponseWriter, r *http.Request) {
}) })
_, _ = w.Write(pubBytes) _, _ = 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))
}
}
Supports Markdown
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