Commit 898a2094 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Requestor can now configure client connect timeout, result jwt expiry

parent 1131c29d
......@@ -95,12 +95,14 @@ type ServerJwt struct {
type RequestorBaseRequest struct {
ResultJwtValidity int `json:"validity"` // Validity of session result JWT in seconds
ClientTimeout int `json:"timeout"` // Wait this many seconds for the IRMA app to connect before the session times out
CallbackUrl string `json:"callbackUrl"` // URL to post session result to
}
type RequestorRequest interface {
Validator
SessionRequest() SessionRequest
Base() RequestorBaseRequest
}
// A ServiceProviderRequest contains a disclosure request.
......@@ -172,6 +174,18 @@ func (r *IdentityProviderRequest) SessionRequest() SessionRequest {
return r.Request
}
func (r *ServiceProviderRequest) Base() RequestorBaseRequest {
return r.RequestorBaseRequest
}
func (r *SignatureRequestorRequest) Base() RequestorBaseRequest {
return r.RequestorBaseRequest
}
func (r *IdentityProviderRequest) Base() RequestorBaseRequest {
return r.RequestorBaseRequest
}
// SessionRequest is an IRMA session.
type SessionRequest interface {
Validator
......@@ -624,7 +638,7 @@ func (claims *SignatureRequestorJwt) Action() Action { return ActionSigning }
func (claims *IdentityProviderJwt) Action() Action { return ActionIssuing }
func SignedRequestorJwt(request SessionRequest, alg jwt.SigningMethod, key interface{}, name string) (string, error) {
func SignSessionRequest(request SessionRequest, alg jwt.SigningMethod, key interface{}, name string) (string, error) {
var jwtcontents RequestorJwt
switch r := request.(type) {
case *IssuanceRequest:
......@@ -636,3 +650,19 @@ func SignedRequestorJwt(request SessionRequest, alg jwt.SigningMethod, key inter
}
return jwtcontents.Sign(alg, key)
}
func SignRequestorRequest(request RequestorRequest, alg jwt.SigningMethod, key interface{}, name string) (string, error) {
var jwtcontents RequestorJwt
switch r := request.(type) {
case *IdentityProviderRequest:
jwtcontents = NewIdentityProviderJwt(name, nil)
jwtcontents.(*IdentityProviderJwt).Request = r
case *ServiceProviderRequest:
jwtcontents = NewServiceProviderJwt(name, nil)
jwtcontents.(*ServiceProviderJwt).Request = r
case *SignatureRequestorRequest:
jwtcontents = NewSignatureRequestorJwt(name, nil)
jwtcontents.(*SignatureRequestorJwt).Request = r
}
return jwtcontents.Sign(alg, key)
}
......@@ -84,7 +84,13 @@ func (s memorySessionStore) deleteExpired() {
expired := make([]string, 0, len(s.m))
for token, session := range s.m {
session.Lock()
if session.lastActive.Add(5 * time.Minute).Before(time.Now()) {
timeout := 5 * time.Minute
if session.status == server.StatusInitialized && session.rrequest.Base().ClientTimeout != 0 {
timeout = time.Duration(session.rrequest.Base().ClientTimeout) * time.Second
}
if session.lastActive.Add(timeout).Before(time.Now()) {
if !session.finished() {
conf.Logger.Infof("Session %s expired", token)
session.markAlive()
......
......@@ -206,7 +206,7 @@ func jwtAuthenticate(
if !claims.VerifyIssuedAt(time.Now().Unix(), true) {
return true, nil, "", server.RemoteError(server.ErrorUnauthorized, "jwt not yet valid")
}
if time.Unix(claims.IssuedAt, 0).Add(10 * time.Minute).Before(time.Now()) { // TODO make configurable
if time.Unix(claims.IssuedAt, 0).Add(time.Duration(conf.MaxRequestAge) * time.Second).Before(time.Now()) {
return true, nil, "", server.RemoteError(server.ErrorUnauthorized, "jwt too old")
}
......
......@@ -47,6 +47,9 @@ type Configuration struct {
// Private key to sign result JWTs with. If absent, /result-jwt and /getproof are disabled.
JwtPrivateKey string `json:"jwtprivatekey" mapstructure:"jwtprivatekey"`
// Max age in seconds of a session request JWT (using iat field)
MaxRequestAge int `json:"maxrequestage" mapstructure:"maxrequestage"`
Verbose int `json:"verbose" mapstructure:"verbose"`
Quiet bool `json:"quiet" mapstructure:"quiet"`
......
......@@ -75,6 +75,7 @@ func setFlags(cmd *cobra.Command) error {
flags.String("cachepath", cachepath, "Directory for writing cache files to")
flags.StringP("jwtissuer", "j", "irmaserver", "JWT issuer")
flags.StringP("jwtprivatekey", "w", "", "JWT private key or path to it")
flags.Int("maxrequestage", 300, "Max age in seconds of a session request JWT")
flags.StringP("url", "u", defaulturl, "External URL to server to which the IRMA client connects")
flags.StringP("listenaddr", "l", "0.0.0.0", "Address at which to listen")
flags.IntP("port", "p", 8088, "Port at which to listen")
......@@ -148,6 +149,7 @@ func configure() error {
GlobalPermissions: irmaserver.Permissions{},
JwtIssuer: viper.GetString("jwtissuer"),
JwtPrivateKey: viper.GetString("jwtprivatekey"),
MaxRequestAge: viper.GetInt("maxrequestage"),
Verbose: viper.GetInt("verbose"),
Quiet: viper.GetBool("quiet"),
}
......
......@@ -227,7 +227,8 @@ func handleJwtResult(w http.ResponseWriter, r *http.Request) {
return
}
res := irmarequestor.GetSessionResult(chi.URLParam(r, "token"))
sessiontoken := chi.URLParam(r, "token")
res := irmarequestor.GetSessionResult(sessiontoken)
if res == nil {
server.WriteError(w, server.ErrorSessionUnknown, "")
return
......@@ -242,6 +243,10 @@ func handleJwtResult(w http.ResponseWriter, r *http.Request) {
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)
......@@ -262,7 +267,8 @@ func handleJwtProofs(w http.ResponseWriter, r *http.Request) {
return
}
res := irmarequestor.GetSessionResult(chi.URLParam(r, "token"))
sessiontoken := chi.URLParam(r, "token")
res := irmarequestor.GetSessionResult(sessiontoken)
if res == nil {
server.WriteError(w, server.ErrorSessionUnknown, "")
return
......@@ -287,6 +293,10 @@ func handleJwtProofs(w http.ResponseWriter, r *http.Request) {
claims["iss"] = conf.JwtIssuer
}
claims["status"] = res.Status
validity := irmarequestor.GetRequest(sessiontoken).Base().ResultJwtValidity
if validity != 0 {
claims["exp"] = time.Now().Unix() + int64(validity)
}
// Disclosed credentials and possibly signature
m := make(map[irma.AttributeTypeIdentifier]string, len(res.Disclosed))
......
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