Implemented and integrated challenge update after every successful challenge
This commit is contained in:
parent
4019689df1
commit
79d8094dc2
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
|
@ -11,6 +12,12 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
// Session names
|
||||
sessionChallenge = "challenge"
|
||||
sessionBlocked = "blocked"
|
||||
)
|
||||
|
||||
type ChallengeError struct {
|
||||
Text string
|
||||
HttpCode int
|
||||
|
@ -56,13 +63,50 @@ func NewChallengeGiver(e *PayloadEncryptor, logger *zap.Logger) (*ChallengeGiver
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
|
||||
func (cg *ChallengeGiver) getSession(r *http.Request) (*sessions.Session, *ChallengeError) {
|
||||
s, err := cg.cookieStore.Get(r, sessionChallenge)
|
||||
if err != nil {
|
||||
cg.logger.Error("checkChallengeResponse: cg.cookieStore.Get(r, sessionChallenge)", zap.Error(err), zap.String("sessionChallenge", sessionChallenge))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (cg *ChallengeGiver) generateNewChallenge(s *sessions.Session, w http.ResponseWriter, r *http.Request) ([]byte, *ChallengeError) {
|
||||
challenge := make([]byte, 64)
|
||||
_, err := rand.Read(challenge)
|
||||
if err != nil {
|
||||
cg.logger.Error("regenerateNewChallenge: _, err = rand.Read(challenge)", zap.Error(err))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
s.Values[sessionChallenge] = challenge
|
||||
err = s.Save(r, w)
|
||||
if err != nil {
|
||||
cg.logger.Error("regenerateNewChallenge: err = s.Save(r, w)", zap.Error(err))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
return challenge, nil
|
||||
}
|
||||
|
||||
func (cg *ChallengeGiver) block(s *sessions.Session, w http.ResponseWriter, r *http.Request) *ChallengeError {
|
||||
s.Values[sessionBlocked] = true
|
||||
err := s.Save(r, w)
|
||||
if err != nil {
|
||||
cg.logger.Error("block: err = s.Save(r, w)", zap.Error(err))
|
||||
return &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
return &ChallengeError{"forbidden", http.StatusForbidden}
|
||||
}
|
||||
|
||||
func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
|
||||
s, ce := cg.getSession(r)
|
||||
if ce != nil {
|
||||
return ce
|
||||
}
|
||||
|
||||
blocked, ok := s.Values[sessionBlocked].(bool)
|
||||
if ok && blocked {
|
||||
return &ChallengeError{"forbidden", http.StatusForbidden}
|
||||
|
@ -89,40 +133,23 @@ func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.
|
|||
// Only if we have both a challenge in the session store and in the request header
|
||||
// do we entertain blocking the client. Because then we know someone is trying to be sneaky.
|
||||
if !bytes.Equal(c, challenge) {
|
||||
s.Values[sessionBlocked] = true
|
||||
err = s.Save(r, w)
|
||||
if err != nil {
|
||||
cg.logger.Error("checkChallengeResponse: err = s.Save(r, w)", zap.Error(err))
|
||||
return &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
return &ChallengeError{"forbidden", http.StatusForbidden}
|
||||
return cg.block(s, w, r)
|
||||
}
|
||||
return nil
|
||||
|
||||
// If every is ok, regenerate the challenge
|
||||
_, ce = cg.generateNewChallenge(s, w, r)
|
||||
return ce
|
||||
}
|
||||
|
||||
func (cg *ChallengeGiver) getChallenge(w http.ResponseWriter, r *http.Request) ([]byte, *ChallengeError) {
|
||||
s, err := cg.cookieStore.Get(r, sessionChallenge)
|
||||
if err != nil {
|
||||
cg.logger.Error("getChallenge: hs.cookieStore.Get(r, sessionChallenge)", zap.Error(err))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
s, ce := cg.getSession(r)
|
||||
if ce != nil {
|
||||
return nil, ce
|
||||
}
|
||||
|
||||
challenge, ok := s.Values[sessionChallenge].([]byte)
|
||||
if !ok {
|
||||
challenge = make([]byte, 64)
|
||||
_, err = rand.Read(challenge)
|
||||
if err != nil {
|
||||
cg.logger.Error("getChallenge: _, err = rand.Read(challenge)", zap.Error(err))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
s.Values[sessionChallenge] = challenge
|
||||
err = s.Save(r, w)
|
||||
if err != nil {
|
||||
cg.logger.Error("getChallenge: err = s.Save(r, w)", zap.Error(err))
|
||||
return nil, &ChallengeError{"error", http.StatusInternalServerError}
|
||||
}
|
||||
challenge, ce = cg.generateNewChallenge(s, w, r)
|
||||
}
|
||||
return challenge, nil
|
||||
}
|
||||
|
@ -139,8 +166,13 @@ func NewChallengeTaker(e *PayloadEncryptor) *ChallengeTaker {
|
|||
}
|
||||
}
|
||||
|
||||
func (ct *ChallengeTaker) SetChallenge(challenge []byte) {
|
||||
func (ct *ChallengeTaker) SetChallenge(resp *http.Response) error {
|
||||
challenge, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ct.serverChallenge = challenge
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ct *ChallengeTaker) DoChallenge(req *http.Request) error {
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
|
@ -95,12 +94,7 @@ func (c *BaseClient) getChallenge() error {
|
|||
return fmt.Errorf("[client] status not ok when getting challenge, received '%s'", resp.Status)
|
||||
}
|
||||
|
||||
challenge, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.challengeTaker.SetChallenge(challenge)
|
||||
return nil
|
||||
return c.challengeTaker.SetChallenge(resp)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -445,6 +439,7 @@ func StartUpReceivingClient(backend *api.GethStatusBackend, cs, configJSON strin
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.getChallenge()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -453,9 +448,19 @@ func StartUpReceivingClient(backend *api.GethStatusBackend, cs, configJSON strin
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.getChallenge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.receiveSyncDeviceData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.getChallenge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.sendInstallationData()
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@ const (
|
|||
pairingReceiveSyncDevice = pairingBase + "/receiveSyncDevice"
|
||||
pairingSendInstallation = pairingBase + "/sendInstallation"
|
||||
pairingReceiveInstallation = pairingBase + "/receiveInstallation"
|
||||
|
||||
// Session names
|
||||
sessionChallenge = "challenge"
|
||||
sessionBlocked = "blocked"
|
||||
)
|
||||
|
||||
// Account handling
|
||||
|
|
|
@ -207,17 +207,22 @@ func (s *PairingServerSuite) TestPairingServer_handlePairingChallengeMiddleware(
|
|||
|
||||
err = c.getChallenge()
|
||||
s.Require().NoError(err)
|
||||
challenge := c.serverChallenge
|
||||
challenge := c.challengeTaker.serverChallenge
|
||||
|
||||
// This is NOT a mistake! Call c.getChallenge() twice to check that the client gets the same challenge
|
||||
// the server will only generate 1 challenge per session per connection
|
||||
// the server will only generate 1 challenge until the challenge is successfully completed
|
||||
err = c.getChallenge()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(challenge, c.serverChallenge)
|
||||
s.Require().Equal(challenge, c.challengeTaker.serverChallenge)
|
||||
|
||||
// receiving account data should now work.
|
||||
err = c.receiveAccountData()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// After a successful challenge the challenge should change
|
||||
err = c.getChallenge()
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEqual(challenge, c.challengeTaker.serverChallenge)
|
||||
}
|
||||
|
||||
func (s *PairingServerSuite) TestPairingServer_handlePairingChallengeMiddleware_block() {
|
||||
|
@ -233,8 +238,8 @@ func (s *PairingServerSuite) TestPairingServer_handlePairingChallengeMiddleware_
|
|||
s.Require().NoError(err)
|
||||
|
||||
// Simulate encrypting with a dodgy key, write some nonsense to the challenge field
|
||||
c.serverChallenge = make([]byte, 64)
|
||||
_, err = rand.Read(c.serverChallenge)
|
||||
c.challengeTaker.serverChallenge = make([]byte, 64)
|
||||
_, err = rand.Read(c.challengeTaker.serverChallenge)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Attempt again to get the account data, should fail
|
||||
|
|
Loading…
Reference in New Issue