Skip to content

Commit

Permalink
return more descriptive error messages on ticket auth failure
Browse files Browse the repository at this point in the history
  • Loading branch information
itswisdomagain committed Aug 21, 2019
1 parent ac462c6 commit 1d4dca5
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 12 deletions.
4 changes: 4 additions & 0 deletions controllers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ func (controller *MainController) API(c web.C, r *http.Request) *system.APIRespo
}
}

if invalidAuthMessage := c.Env["InvalidTicketAuthMessage"]; invalidAuthMessage != "" && code == codes.Unauthenticated {
err = fmt.Errorf("error processing ticket auth data: %s", invalidAuthMessage)
}

if err != nil {
status = "error"
response = response + " - " + err.Error()
Expand Down
7 changes: 5 additions & 2 deletions v3api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ func (v3Api *V3API) ApplyTicketAuth(c *web.C, h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/v3") {
authHeader := r.Header.Get("Authorization")
msa := v3Api.validateTicketOwnership(authHeader)
if msa != "" {
msa, invalidAuthResponse := v3Api.validateTicketOwnership(authHeader)
if invalidAuthResponse != "" {
log.Warnf(invalidAuthResponse)
c.Env["InvalidTicketAuthMessage"] = invalidAuthResponse
} else if msa != "" {
dbMap := c.Env["DbMap"].(*gorp.DbMap)

user, err := models.GetUserByMSA(dbMap, msa)
Expand Down
21 changes: 11 additions & 10 deletions v3api/ticketauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/decred/dcrd/dcrutil"
"github.com/decred/dcrwallet/wallet"
"fmt"
)

const (
Expand All @@ -19,41 +20,41 @@ const (
MaxTicketChallengeAge = 60 * 30 // 30 minutes
)

func (v3Api *V3API) validateTicketOwnership(authHeader string) (multiSigAddress string) {
func (v3Api *V3API) validateTicketOwnership(authHeader string) (multiSigAddress, authValidationFailureReason string) {
if !strings.HasPrefix(authHeader, customAuthScheme) {
log.Warnf("invalid API v3 auth header value %s", authHeader)
authValidationFailureReason = fmt.Sprintf("invalid API v3 auth header value %s", authHeader)
return
}

timestamp, timestampSignature, ticketHash := extractAuthParams(strings.TrimPrefix(authHeader, customAuthScheme))
if timestamp == "" || timestampSignature == "" || ticketHash == "" {
log.Warnf("invalid API v3 auth header value %s", authHeader)
authValidationFailureReason = fmt.Sprintf("invalid API v3 auth header value %s", authHeader)
return
}

// Ensure that this signature had not been used in a previous authentication attempt.
if v3Api.processedTicketChallenges.containsChallenge(timestampSignature) {
log.Warnf("disallowed reuse of ticket auth signature %v", timestampSignature)
authValidationFailureReason = fmt.Sprintf("disallowed reuse of ticket auth signature %v", timestampSignature)
return
}

authTimestamp, err := strconv.Atoi(timestamp)
if err != nil {
log.Warnf("invalid ticket auth timestamp value %v", timestamp)
authValidationFailureReason = fmt.Sprintf("invalid ticket auth timestamp value %v", timestamp)
return
}

// Ensure that the auth timestamp is not in the future and is not more than 30 seconds into the past.
timestampDelta := time.Now().Unix() - int64(authTimestamp)
if timestampDelta < 0 || timestampDelta > v3Api.ticketChallengeMaxAge {
log.Warnf("expired ticket auth timestamp value %v", timestamp)
authValidationFailureReason = fmt.Sprintf("expired ticket auth timestamp value %v", timestamp)
return
}

// confirm that the timestamp signature is a valid base64 string
decodedSignature, err := base64.StdEncoding.DecodeString(timestampSignature)
if err != nil {
log.Warnf("invalid ticket auth signature %s", timestampSignature)
authValidationFailureReason = fmt.Sprintf("invalid ticket auth signature %s", timestampSignature)
return
}

Expand All @@ -67,20 +68,20 @@ func (v3Api *V3API) validateTicketOwnership(authHeader string) (multiSigAddress
// todo: may be better to maintain a memory map of tickets-userWalletAddresses
ticketInfo, err := v3Api.stakepooldConnMan.GetTicketInfo(ticketHash)
if err != nil {
log.Warnf("ticket auth, get ticket info failed: %v", err)
authValidationFailureReason = fmt.Sprintf("ticket auth, get ticket info failed: %v", err)
return
}

// check if timestamp signature checks out against address
addr, err := dcrutil.DecodeAddress(ticketInfo.OwnerFeeAddress)
if err != nil {
log.Errorf("ticket auth, unexpected decode address error: %v", err)
authValidationFailureReason = fmt.Sprintf("ticket auth, unexpected decode address error: %v", err)
return
}

valid, err := wallet.VerifyMessage(timestamp, addr, decodedSignature)
if err != nil {
log.Errorf("error validating timestamp signature for ticket auth %v", err)
authValidationFailureReason = fmt.Sprintf("error validating timestamp signature for ticket auth %v", err)
return
}

Expand Down

0 comments on commit 1d4dca5

Please sign in to comment.