Implement NewFullToken for Auth.
Add a couple test stubs for this and wallet.
This commit is contained in:
parent
5d297b04bb
commit
52ed6d8d2c
6 changed files with 140 additions and 22 deletions
41
auth.go
41
auth.go
|
@ -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
23
auth_test.go
Normal 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?)")
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)")
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue