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
import "time"
import (
"crypto/rand"
"encoding/hex"
"fmt"
"time"
)
// TODO - Learn how to use https://github.com/golang/oauth2 instead
// TODO - Look into jwt, etc.
@ -10,24 +15,24 @@ type AuthTokenString string
type PublicKey string
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
// for future request:
// IsDownloadKeyValid(DownloadKey) bool
// IsValidToken(AuthTokenString) bool
}
type Auth struct{}
func (a *Auth) IsValidSignature(pubKey PublicKey, payload string, signature string) bool {
// TODO
return false
// TODO - a real check
return signature == "Good Signature"
}
type AuthToken struct {
Token AuthTokenString `json:"token"`
DeviceID string `json:"deviceId"`
Scope string `json:"scope"`
PubKey PublicKey `json:"publicKey"`
Expiration *time.Time `json:"expiration"`
}
@ -42,17 +47,19 @@ func (s *Server) validateTokenRequest(tokenRequest *TokenRequest) bool {
return true
}
func (a *Auth) NewToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) {
/*
TODO
const tokenLength = 32
authToken := auth.AuthToken(
token: random(),
deviceID: tokenRequest.deviceID,
scope: "*", // "download" for a downloadToken
expiration= now() + 2 weeks,
pubkey?
)
*/
return &AuthToken{}, nil
func (a *Auth) NewFullToken(pubKey PublicKey, tokenRequest *TokenRequest) (*AuthToken, error) {
b := make([]byte, tokenLength)
if _, err := rand.Read(b); err != nil {
return nil, fmt.Errorf("Error generating token: %+v", err)
}
return &AuthToken{
Token: AuthTokenString(hex.EncodeToString(b)),
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
// TODO some of the same things tested as server_test, except without any of the mocking
// probably should do the httptest.NewServer thing
// https://medium.com/what-i-talk-about-when-i-talk-about-technology/go-code-examples-httptest-newserver-f965fb349884
import (
"bytes"
"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
}
authToken, err := s.auth.NewToken(authRequest.PubKey, &tokenRequest)
authToken, err := s.auth.NewFullToken(authRequest.PubKey, &tokenRequest)
if err != nil {
errorJSON(w, http.StatusInternalServerError, "Error generating auth token")

View file

@ -26,7 +26,7 @@ type TestAuth struct {
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 {
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
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{
Token: "seekrit-1",
DeviceID: "dID",
Scope: "*",
PubKey: "pubKey",
}
@ -99,6 +100,7 @@ func TestStoreUpdateToken(t *testing.T) {
authToken1 := AuthToken{
Token: "seekrit-1",
DeviceID: "dID",
Scope: "*",
PubKey: "pubKey",
}
authToken2 := authToken1
@ -160,6 +162,7 @@ func TestStoreSaveToken(t *testing.T) {
authToken_d1_1 := AuthToken{
Token: "seekrit-d1-1",
DeviceID: "dID-1",
Scope: "*",
PubKey: "pubKey",
}
@ -268,6 +271,7 @@ func TestStoreGetToken(t *testing.T) {
authToken := AuthToken{
Token: "seekrit-d1",
DeviceID: "dID",
Scope: "*",
PubKey: "pubKey",
}