Implement NewFullToken for Auth.

Add a couple test stubs for this and wallet.
This commit is contained in:
Daniel Krol 2021-12-23 22:29:02 -05:00
parent 5d297b04bb
commit 52ed6d8d2c
6 changed files with 140 additions and 22 deletions

41
auth.go
View file

@ -1,6 +1,11 @@
package main // TODO - make it its own `auth` package later package main // TODO - make it its own `auth` package later
import "time" import (
"crypto/rand"
"encoding/hex"
"fmt"
"time"
)
// TODO - Learn how to use https://github.com/golang/oauth2 instead // TODO - Learn how to use https://github.com/golang/oauth2 instead
// TODO - Look into jwt, etc. // TODO - Look into jwt, etc.
@ -10,24 +15,24 @@ type AuthTokenString string
type PublicKey string type PublicKey string
type AuthInterface interface { type AuthInterface interface {
NewToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) NewFullToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error)
IsValidSignature(pubKey PublicKey, payload string, signature string) bool IsValidSignature(pubKey PublicKey, payload string, signature string) bool
// for future request: // for future request:
// IsDownloadKeyValid(DownloadKey) bool
// IsValidToken(AuthTokenString) bool // IsValidToken(AuthTokenString) bool
} }
type Auth struct{} type Auth struct{}
func (a *Auth) IsValidSignature(pubKey PublicKey, payload string, signature string) bool { func (a *Auth) IsValidSignature(pubKey PublicKey, payload string, signature string) bool {
// TODO // TODO - a real check
return false return signature == "Good Signature"
} }
type AuthToken struct { type AuthToken struct {
Token AuthTokenString `json:"token"` Token AuthTokenString `json:"token"`
DeviceID string `json:"deviceId"` DeviceID string `json:"deviceId"`
Scope string `json:"scope"`
PubKey PublicKey `json:"publicKey"` PubKey PublicKey `json:"publicKey"`
Expiration *time.Time `json:"expiration"` Expiration *time.Time `json:"expiration"`
} }
@ -42,17 +47,19 @@ func (s *Server) validateTokenRequest(tokenRequest *TokenRequest) bool {
return true return true
} }
func (a *Auth) NewToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) { const tokenLength = 32
/*
TODO
authToken := auth.AuthToken( func (a *Auth) NewFullToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) {
token: random(), b := make([]byte, tokenLength)
deviceID: tokenRequest.deviceID, if _, err := rand.Read(b); err != nil {
scope: "*", // "download" for a downloadToken return nil, fmt.Errorf("Error generating token: %+v", err)
expiration= now() + 2 weeks, }
pubkey?
) return &AuthToken{
*/ Token: AuthTokenString(hex.EncodeToString(b)),
return &AuthToken{}, nil DeviceID: tokenRequest.DeviceID,
Scope: "*",
PubKey: pubKey,
// TODO add Expiration here instead of putting it in store.go. and thus redo store.go. d'oh.
}, nil
} }

23
auth_test.go Normal file
View file

@ -0,0 +1,23 @@
package main
import (
"testing"
)
// Test stubs for now
func TestAuthSignaturePass(t *testing.T) {
t.Fatalf("Valid siganture passes")
}
func TestAuthSignatureFail(t *testing.T) {
t.Fatalf("Valid siganture fails")
}
func TestAuthNewFullTokenSuccess(t *testing.T) {
t.Fatalf("New token passes")
}
func TestAuthNewFullTokenFail(t *testing.T) {
t.Fatalf("New token fails (error generating random string? others?)")
}

View file

@ -1,5 +1,73 @@
package main package main
// TODO some of the same things tested as server_test, except without any of the mocking import (
// probably should do the httptest.NewServer thing "bytes"
// https://medium.com/what-i-talk-about-when-i-talk-about-technology/go-code-examples-httptest-newserver-f965fb349884 "encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
// TODO - test some unhappy paths? Don't want to retest all the unit tests though.
func checkStatusCode(t *testing.T, statusCode int) {
if want, got := http.StatusOK, statusCode; want != got {
t.Errorf("StatusCode: expected %s (%d), got %s (%d)", http.StatusText(want), want, http.StatusText(got), got)
}
}
func request(t *testing.T, method string, handler func(http.ResponseWriter, *http.Request), path string, jsonResult interface{}, requestBody string) ([]byte, int) {
req := httptest.NewRequest(
method,
path,
bytes.NewBuffer([]byte(requestBody)),
)
w := httptest.NewRecorder()
handler(w, req)
responseBody, _ := ioutil.ReadAll(w.Body)
err := json.Unmarshal(responseBody, &jsonResult)
if err != nil {
t.Errorf("Error unmarshalling response body err: %+v body: %s", err, responseBody)
}
return responseBody, w.Result().StatusCode
}
func TestIntegrationFlow(t *testing.T) {
store, tmpFile := storeTestInit(t)
defer storeTestCleanup(tmpFile)
s := Server{
&Auth{},
&store,
}
var authToken AuthToken
responseBody, statusCode := request(
t,
http.MethodPost,
s.getAuthToken,
PathGetAuthToken,
&authToken,
`{
"tokenRequestJSON": "{\"deviceID\": \"devID\"}",
"publickey": "testPubKey",
"signature": "Good Signature"
}`,
)
checkStatusCode(t, statusCode)
// result.Token is in hex, tokenLength is bytes in the original
expectedTokenLength := tokenLength * 2
if len(authToken.Token) != expectedTokenLength {
t.Errorf("Expected auth response to contain token length 32: result: %+v", string(responseBody))
}
if authToken.DeviceID != "devID" {
t.Errorf("Unexpected auth response DeviceID. want: %+v got: %+v", "devID", authToken.DeviceID)
}
}

View file

@ -147,7 +147,7 @@ func (s *Server) getAuthToken(w http.ResponseWriter, req *http.Request) {
// TODO // TODO
} }
authToken, err := s.auth.NewToken(authRequest.PubKey, &tokenRequest) authToken, err := s.auth.NewFullToken(authRequest.PubKey, &tokenRequest)
if err != nil { if err != nil {
errorJSON(w, http.StatusInternalServerError, "Error generating auth token") errorJSON(w, http.StatusInternalServerError, "Error generating auth token")

View file

@ -26,7 +26,7 @@ type TestAuth struct {
FailGenToken bool FailGenToken bool
} }
func (a *TestAuth) NewToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) { func (a *TestAuth) NewFullToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) {
if a.FailGenToken { if a.FailGenToken {
return nil, fmt.Errorf("Test error: fail to generate token") return nil, fmt.Errorf("Test error: fail to generate token")
} }
@ -204,3 +204,19 @@ func TestServerValidateTokenRequest(t *testing.T) {
// also add a basic test case for this in TestAuthHandlerErrors to make sure it's called at all // also add a basic test case for this in TestAuthHandlerErrors to make sure it's called at all
t.Fatalf("Implement and test validateTokenRequest") t.Fatalf("Implement and test validateTokenRequest")
} }
func TestServerGetWalletSuccess(t *testing.T) {
t.Fatalf("GetWallet succeeds")
}
func TestServerGetWalletErrors(t *testing.T) {
t.Fatalf("GetWallet fails for various reasons (malformed, auth, db fail)")
}
func TestServerPutWalletSuccess(t *testing.T) {
t.Fatalf("GetWallet succeeds")
}
func TestServerPutWalletErrors(t *testing.T) {
t.Fatalf("GetWallet fails for various reasons (malformed, auth, db fail)")
}

View file

@ -43,6 +43,7 @@ func TestStoreInsertToken(t *testing.T) {
authToken1 := AuthToken{ authToken1 := AuthToken{
Token: "seekrit-1", Token: "seekrit-1",
DeviceID: "dID", DeviceID: "dID",
Scope: "*",
PubKey: "pubKey", PubKey: "pubKey",
} }
@ -99,6 +100,7 @@ func TestStoreUpdateToken(t *testing.T) {
authToken1 := AuthToken{ authToken1 := AuthToken{
Token: "seekrit-1", Token: "seekrit-1",
DeviceID: "dID", DeviceID: "dID",
Scope: "*",
PubKey: "pubKey", PubKey: "pubKey",
} }
authToken2 := authToken1 authToken2 := authToken1
@ -160,6 +162,7 @@ func TestStoreSaveToken(t *testing.T) {
authToken_d1_1 := AuthToken{ authToken_d1_1 := AuthToken{
Token: "seekrit-d1-1", Token: "seekrit-d1-1",
DeviceID: "dID-1", DeviceID: "dID-1",
Scope: "*",
PubKey: "pubKey", PubKey: "pubKey",
} }
@ -268,6 +271,7 @@ func TestStoreGetToken(t *testing.T) {
authToken := AuthToken{ authToken := AuthToken{
Token: "seekrit-d1", Token: "seekrit-d1",
DeviceID: "dID", DeviceID: "dID",
Scope: "*",
PubKey: "pubKey", PubKey: "pubKey",
} }