Skip to content
Snippets Groups Projects
Commit 2e50a3ff authored by Loïck Bonniot's avatar Loïck Bonniot Committed by Tristan Claverie
Browse files

[dfssp] Platform create user

parent fc16f702
No related branches found
No related tags found
1 merge request!24178 platform create user
Pipeline #
......@@ -6,6 +6,8 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"github.com/pborman/uuid"
"math/big"
"time"
)
......@@ -38,6 +40,11 @@ func GetCertificateRequest(country, organization, unit, mail string, key *rsa.Pr
// PEMToCertificateRequest tries to decode a PEM-encoded array of bytes to a certificate request
func PEMToCertificateRequest(data []byte) (*x509.CertificateRequest, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("Couldn't decode the PEM data as a x509 Certificate request")
}
return x509.ParseCertificateRequest(block.Bytes)
}
......@@ -108,3 +115,13 @@ func PEMToCertificate(data []byte) (*x509.Certificate, error) {
block, _ := pem.Decode(data)
return x509.ParseCertificate(block.Bytes)
}
// GenerateUID generates a unique identifier as a uint64
func GenerateUID() uint64 {
// Generating and converting the uuid to fit our needs: an 8 bytes unsigned integer
uuid := uuid.NewRandom()
var slice []byte
slice = uuid[:8]
// TODO: improve this conversion method/need
return new(big.Int).SetBytes(slice).Uint64()
}
......@@ -88,6 +88,12 @@ func TestPEMToCertificateRequest(t *testing.T) {
t.Fatal("Wrong CN: ", res.Subject.CommonName)
}
res, err = PEMToCertificateRequest([]byte("invalid"))
if err == nil {
t.Fatal("The request should not have been decoded as is was invalid format")
}
}
func TestGetSelfSignedCertificate(t *testing.T) {
......
......@@ -74,7 +74,7 @@ func (x ErrorCode_Code) String() string {
func (ErrorCode_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1, 0} }
// RegisterRequest message contains the client's email adress and his
// certificate request
// request (ie the PEM-encoded certificate request)
type RegisterRequest struct {
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
Request string `protobuf:"bytes,2,opt,name=request" json:"request,omitempty"`
......
......@@ -12,7 +12,7 @@ service Platform {
}
// RegisterRequest message contains the client's email adress and his
// certificate request
// request (ie the PEM-encoded certificate request)
message RegisterRequest {
string email = 1;
string request = 2;
......
......@@ -4,9 +4,7 @@ import (
"crypto/rsa"
"crypto/x509"
"dfss/auth"
"github.com/pborman/uuid"
"io/ioutil"
"math/big"
"os/user"
"path/filepath"
)
......@@ -35,14 +33,9 @@ func GetHomeDir() string {
return usr.HomeDir
}
// GenerateRootCA constructs a self-signed certificate, using a unique serial number randomly generated (see UUID)
// GenerateRootCA constructs a self-signed certificate, using a unique serial number randomly generated
func GenerateRootCA(days int, country, organization, unit, cn string, key *rsa.PrivateKey) ([]byte, error) {
// Generating and converting the uuid to fit our needs: an 8 bytes integer.
uuid := uuid.NewRandom()
var slice []byte
slice = uuid[:8]
// TODO: improve this conversion method/need
serial := new(big.Int).SetBytes(slice).Uint64()
serial := auth.GenerateUID()
cert, err := auth.GetSelfSignedCertificate(days, serial, country, organization, unit, cn, key)
......
......@@ -71,8 +71,8 @@ func ExampleInitialize() {
fmt.Println(err)
}
checkFile(keyPath, "Private key")
checkFile(certPath, "Certificate")
CheckFile(keyPath, "Private key")
CheckFile(certPath, "Certificate")
// Output:
// Private key file has been found
......@@ -81,7 +81,7 @@ func ExampleInitialize() {
// Certificate file has been deleted
}
func checkFile(path, name string) {
func CheckFile(path, name string) {
if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Println(name + " file couldn't be found")
} else {
......
......@@ -40,7 +40,7 @@ func TestMain(m *testing.M) {
// Start platform server
keyPath := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata")
srv := server.GetServer(keyPath, dbURI, true)
srv := server.GetServer(keyPath, dbURI, 365, true)
go func() { _ = net.Listen("localhost:9090", srv) }()
// Run
......
......@@ -15,7 +15,7 @@ import (
var (
verbose, demo bool
path, country, org, unit, cn, port, address, dbURI string
keySize, validity int
keySize, rootValidity, certValidity int
)
func init() {
......@@ -33,7 +33,8 @@ func init() {
flag.StringVar(&cn, "cn", "dfssp", "Common name for the root certificate")
flag.IntVar(&keySize, "keySize", 512, "Encoding size for the private key")
flag.IntVar(&validity, "validity", 21, "Root certificate's validity duration (days)")
flag.IntVar(&rootValidity, "rootValidity", 365, "Root certificate's validity duration (days)")
flag.IntVar(&certValidity, "certValidity", 365, "Validity duration for the certificates generated by this platform (days)")
flag.StringVar(&dbURI, "db", "mongodb://localhost/dfss", "Name of the environment variable containing the server url in standard MongoDB format")
......@@ -45,7 +46,7 @@ func init() {
fmt.Println(" dfssp [flags] command")
fmt.Println("\nThe commands are:")
fmt.Println(" init [cn, country, keySize, org, path, unit, validity]")
fmt.Println(" init [cn, country, keySize, org, path, unit, rootValidity]")
fmt.Println(" create and save the platform's private key and root certificate")
fmt.Println(" start [path, db, a, p]")
fmt.Println(" start the platform after loading its private key and root certificate")
......@@ -68,14 +69,14 @@ func main() {
case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "init":
err := authority.Initialize(keySize, validity, country, org, unit, cn, path)
err := authority.Initialize(keySize, rootValidity, country, org, unit, cn, path)
if err != nil {
fmt.Println("An error occured during the initialization operation:", err)
os.Exit(1)
}
dapi.DLog("Private key generated !")
case "start":
srv := server.GetServer(path, dbURI, verbose)
srv := server.GetServer(path, dbURI, certValidity, verbose)
fmt.Println("Listening on " + address + ":" + port)
dapi.DLog("Platform server started on " + address + ":" + port)
err := net.Listen(address+":"+port, srv)
......
......@@ -7,6 +7,7 @@ import (
"dfss/dfssp/api"
"dfss/dfssp/authority"
"dfss/dfssp/contract"
"dfss/dfssp/user"
"dfss/mgdb"
"dfss/net"
"golang.org/x/net/context"
......@@ -14,26 +15,24 @@ import (
)
type platformServer struct {
Pid *authority.PlatformID
DB *mgdb.MongoManager
Verbose bool
Pid *authority.PlatformID
DB *mgdb.MongoManager
CertDuration int
Verbose bool
}
// Register handler
//
// Handle incoming RegisterRequest messages
func (s *platformServer) Register(ctx context.Context, in *api.RegisterRequest) (*api.ErrorCode, error) {
// TODO
_ = new(platformServer)
return nil, nil
return user.Register(s.DB, in)
}
// Auth handler
//
// Handle incoming AuthRequest messages
func (s *platformServer) Auth(ctx context.Context, in *api.AuthRequest) (*api.RegisteredUser, error) {
// TODO
return nil, nil
return user.Auth(s.Pid, s.DB, s.CertDuration, in)
}
// Unregister handler
......@@ -69,7 +68,7 @@ func (s *platformServer) ReadySign(ctx context.Context, in *api.ReadySignRequest
}
// GetServer returns the GRPC server associated with the platform
func GetServer(keyPath, db string, verbose bool) *grpc.Server {
func GetServer(keyPath, db string, certValidity int, verbose bool) *grpc.Server {
pid, err := authority.Start(keyPath)
if err != nil {
fmt.Println("An error occured during the private key and root certificate retrieval:", err)
......@@ -84,9 +83,10 @@ func GetServer(keyPath, db string, verbose bool) *grpc.Server {
server := net.NewServer(pid.RootCA, pid.Pkey, pid.RootCA)
api.RegisterPlatformServer(server, &platformServer{
Pid: pid,
DB: dbManager,
Verbose: verbose,
Pid: pid,
DB: dbManager,
CertDuration: certValidity,
Verbose: verbose,
})
return server
}
......@@ -24,6 +24,7 @@ func Init() {
_ = template.Must(tpl.Parse("{{define `signature`}}" + signature + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `invitation`}}" + invitation + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `contractDetails`}}" + contractDetails + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `verificationMail`}}" + verificationMail + "{{end}}"))
ready = true
}
......
package templates
const verificationMail = `Dear sir or Madam,
You asked to register to the DFSS platform.
Please send us your authentication request with
the following text as token:
{{.Token}}
If you did not asked for registration, we deeply excuse
for the error.
{{template "signature"}}
`
// VerificationMail contains the token to be sent in the verification mail
type VerificationMail struct {
Token string
}
package user
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"errors"
"fmt"
"io"
"time"
"dfss/auth"
"dfss/dfssp/api"
"dfss/dfssp/authority"
"dfss/dfssp/entities"
"dfss/dfssp/templates"
"dfss/mgdb"
"gopkg.in/mgo.v2/bson"
)
// Check if the registration request has usable fields
func checkRegisterRequest(in *api.RegisterRequest) *api.ErrorCode {
if len(in.Email) == 0 {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "Invalid email length"}
}
if len(in.Request) == 0 {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "Invalid request length"}
}
_, err := auth.PEMToCertificateRequest([]byte(in.Request))
if err != nil {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: err.Error()}
}
return nil
}
// Send the verification email in response to the specified registration request
//
// This method should only be called AFTER checking the RegisterRequest for validity
func sendVerificationMail(in *api.RegisterRequest, token string) error {
conn := templates.MailConn()
if conn == nil {
return errors.New("Couldn't connect to the dfssp mail server")
}
defer func() { _ = conn.Close() }()
rcpts := []string{in.Email}
mail := templates.VerificationMail{Token: token}
content, err := templates.Get("verificationMail", mail)
if err != nil {
return err
}
err = conn.Send(
rcpts,
"[DFSS] Registration email validation",
content,
nil,
nil,
nil,
)
if err != nil {
return err
}
return nil
}
// Register checks if the registration request is valid, and if so,
// creates the user entry in the database
//
// If there is already an entry in the database with the same email,
// evaluates the request as invalid
//
// The user's ConnectionInfo field is NOT handled here
// This data should be gathered upon beginning the signing sequence
func Register(manager *mgdb.MongoManager, in *api.RegisterRequest) (*api.ErrorCode, error) {
// Check the request validity
errCode := checkRegisterRequest(in)
if errCode != nil {
return errCode, nil
}
// Generating the random token
b := make([]byte, 8)
_, err := rand.Read(b)
if err != nil {
return &api.ErrorCode{Code: api.ErrorCode_INTERR, Message: "Error during the generation of the token"}, nil
}
token := fmt.Sprintf("%x", b)
// If there is already an entry with the same mail, do nothing
var res []entities.User
err = manager.Get("users").FindAll(bson.M{
"email": bson.M{"$eq": in.Email},
}, &res)
if len(res) != 0 {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "An entry already exists with the same mail"}, nil
}
// Creating the new user
user := entities.NewUser()
user.Email = in.Email
user.RegToken = token
user.Csr = in.Request
// Adding the new user in the database
ok, err := manager.Get("users").Insert(*user)
if !ok {
return &api.ErrorCode{Code: api.ErrorCode_INTERR, Message: "Error during the insertion of the new user"}, err
}
// Sending the email
err = sendVerificationMail(in, token)
if err != nil {
return &api.ErrorCode{Code: api.ErrorCode_INTERR, Message: "Error during the sending of the email"}, err
}
return &api.ErrorCode{Code: api.ErrorCode_SUCCESS, Message: "Registration successful ; email sent"}, nil
}
// Check if the authentication request has usable fields
func checkAuthRequest(in *api.AuthRequest, certDuration int) error {
if len(in.Email) == 0 {
return errors.New("Invalid email length")
}
if len(in.Token) == 0 {
return errors.New("Invalid token length")
}
if certDuration < 1 {
return errors.New("Invalid validity duration")
}
return nil
}
// Check if the authentication request was made in time
func checkTokenTimeout(user *entities.User) error {
now := time.Now().UTC()
bad := now.After(user.Registration.Add(time.Hour * 24))
if bad {
return errors.New("Registration request is over 24 hours old")
}
return nil
}
// Gerenate the user's certificate and certificate hash according to the specified parameters
//
// This function should only be called AFTER checking the AuthRequest for validity
func generateUserCert(csr string, certDuration int, parent *x509.Certificate, key *rsa.PrivateKey) ([]byte, []byte, error) {
x509csr, err := auth.PEMToCertificateRequest([]byte(csr))
if err != nil {
return nil, nil, err
}
cert, err := auth.GetCertificate(certDuration, auth.GenerateUID(), x509csr, parent, key)
if err != nil {
return nil, nil, err
}
h := sha512.New()
_, err = io.WriteString(h, string(cert))
if err != nil {
return nil, nil, err
}
certHash := h.Sum(nil)
return cert, certHash, nil
}
// Auth checks if the authentication request is valid, and if so,
// generate the certificate and certificate hash for the user, and
// updates the user's entry in the database
//
// If there is already an entry in the database with the same email,
// and that this entry already has a certificate and certificate hash,
// evaluates the request as invalid
//
// The user's ConnectionInfo field is NOT handled here
// This data should be gathered upon beginning the signing sequence
func Auth(pid *authority.PlatformID, manager *mgdb.MongoManager, certDuration int, in *api.AuthRequest) (*api.RegisteredUser, error) {
// Check the request validity
err := checkAuthRequest(in, certDuration)
if err != nil {
return nil, err
}
// Find the user in the database
var user entities.User
err = manager.Get("users").Collection.Find(bson.M{
"email": bson.M{"$eq": in.Email},
}).One(&user)
if err != nil {
return nil, err
}
// If the user already has a certificate and certificate hash in the database, does nothing
if user.Certificate != "" || user.CertHash != "" {
return nil, errors.New("User is already registered")
}
// Check if the delta between now and the moment the user was created (ie the moment he sent the register request) is in bound of 24h
err = checkTokenTimeout(&user)
if err != nil {
return nil, err
}
// Check if the token is correct
if in.Token != user.RegToken {
return nil, errors.New("Token mismatch")
}
// Generate the certificates and hash
cert, certHash, err := generateUserCert(user.Csr, certDuration, pid.RootCA, pid.Pkey)
if err != nil {
return nil, err
}
user.Certificate = string(cert)
user.CertHash = string(certHash)
// Updating the database
ok, err := manager.Get("users").UpdateByID(user)
if !ok {
return nil, err
}
// Returning the RegisteredUser message
return &api.RegisteredUser{ClientCert: user.Certificate}, nil
}
package user_test
import (
"dfss/dfssp/api"
"dfss/net"
"github.com/bmizerany/assert"
"golang.org/x/net/context"
"testing"
)
const (
// ValidServ is a host/port adress to a platform server with bad setup
ValidServ = "localhost:9090"
// InvalidServ is a host/port adress to a platform server with bad setup
InvalidServ = "localhost:9091"
)
func clientTest(t *testing.T, hostPort string) api.PlatformClient {
conn, err := net.Connect(hostPort, nil, nil, rootCA)
if err != nil {
t.Fatal("Unable to connect: ", err)
}
return api.NewPlatformClient(conn)
}
func TestWrongRegisterRequest(t *testing.T) {
client := clientTest(t, ValidServ)
request := &api.RegisterRequest{}
errCode, err := client.Register(context.Background(), request)
assert.Equal(t, nil, err)
assert.Equal(t, errCode.Code, api.ErrorCode_INVARG)
request.Email = "foo"
errCode, err = client.Register(context.Background(), request)
assert.Equal(t, nil, err)
assert.Equal(t, errCode.Code, api.ErrorCode_INVARG)
request.Request = "foo"
errCode, err = client.Register(context.Background(), request)
assert.Equal(t, nil, err)
assert.Equal(t, errCode.Code, api.ErrorCode_INVARG)
}
func TestWrongAuthRequest(t *testing.T) {
// Get a client to the invalid server (cert duration is -1)
client := clientTest(t, InvalidServ)
// Invalid mail length
inv := &api.AuthRequest{}
msg, err := client.Auth(context.Background(), inv)
if msg != nil || err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
// Invalid token length
inv.Email = "foo"
msg, err = client.Auth(context.Background(), inv)
if msg != nil || err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
// Invalid certificate validity duration
inv.Token = "foo"
msg, err = client.Auth(context.Background(), inv)
if msg != nil || err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
}
func TestAuthUserNotFound(t *testing.T) {
mail := "wrong@wrong.wrong"
token := "wrong"
client := clientTest(t, ValidServ)
request := &api.AuthRequest{Email: mail, Token: token}
msg, err := client.Auth(context.Background(), request)
assert.Equal(t, (*api.RegisteredUser)(nil), msg)
if err == nil {
t.Fatal("The request user should not have been found in the database")
}
}
package user
// TODO: include code here
package user
package user_test
import (
"crypto/rsa"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"dfss/auth"
"dfss/dfssp/api"
"dfss/dfssp/entities"
"dfss/dfssp/server"
"dfss/mgdb"
"dfss/net"
"github.com/bmizerany/assert"
"golang.org/x/net/context"
"gopkg.in/mgo.v2/bson"
"time"
)
var (
mail string
csr []byte
rootCA *x509.Certificate
rootKey, pkey *rsa.PrivateKey
)
func init() {
mail = "foo@foo.foo"
pkey, _ = auth.GeneratePrivateKey(512)
path := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata", "dfssp_rootCA.pem")
CAData, _ := ioutil.ReadFile(path)
rootCA, _ = auth.PEMToCertificate(CAData)
path = filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata", "dfssp_pkey.pem")
KeyData, _ := ioutil.ReadFile(path)
rootKey, _ = auth.PEMToPrivateKey(KeyData)
csr, _ = auth.GetCertificateRequest("country", "organization", "unit", mail, pkey)
}
var err error
var collection *mgdb.MongoCollection
var manager *mgdb.MongoManager
......@@ -21,14 +56,24 @@ func TestMain(m *testing.M) {
dbURI = os.Getenv("DFSS_MONGO_URI")
if dbURI == "" {
dbURI = "mongodb://localhost/dfss"
dbURI = "mongodb://localhost/dfss-test"
}
manager, err = mgdb.NewManager(dbURI)
collection = manager.Get("demo")
collection = manager.Get("users")
repository = entities.NewUserRepository(collection)
keyPath := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata")
// Valid server
srv := server.GetServer(keyPath, dbURI, 365, true)
go func() { _ = net.Listen(ValidServ, srv) }()
// Server using invalid certificate duration
srv2 := server.GetServer(keyPath, dbURI, -1, true)
go func() { _ = net.Listen(InvalidServ, srv2) }()
// Run
code := m.Run()
......@@ -65,8 +110,6 @@ func TestMongoInsertUser(t *testing.T) {
if err != nil {
t.Fatal("An error occurred while inserting the user")
}
fmt.Println("Successfully inserted a user")
}
func equalUsers(t *testing.T, user1, user2 *entities.User) {
......@@ -150,3 +193,173 @@ func TestMongoFetchIncompleteUser(t *testing.T) {
equalUsers(t, &user, fetched)
}
func TestWrongAuthRequestContext(t *testing.T) {
mail := "right@right.right"
token := "right"
user := entities.NewUser()
user.Email = mail
user.RegToken = token
user.Registration = time.Now().UTC().Add(time.Hour * -48)
_, err := repository.Collection.Insert(*user)
if err != nil {
t.Fatal(err)
}
client := clientTest(t, ValidServ)
request := &api.AuthRequest{Email: mail, Token: "foo"}
// Token timeout
msg, err := client.Auth(context.Background(), request)
assert.Equal(t, (*api.RegisteredUser)(nil), msg)
if err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
// Token mismatch
user.Registration = time.Now().UTC()
_, err = repository.Collection.UpdateByID(*user)
if err != nil {
t.Fatal(err)
}
msg, err = client.Auth(context.Background(), request)
assert.Equal(t, (*api.RegisteredUser)(nil), msg)
if err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
res := entities.User{}
err = repository.Collection.FindByID(*user, &res)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, res.Certificate, "")
assert.Equal(t, res.CertHash, "")
// Invalid certificate request (none here)
request.Token = token
msg, err = client.Auth(context.Background(), request)
assert.Equal(t, (*api.RegisteredUser)(nil), msg)
if err == nil {
t.Fatal("The request should have been evaluated as invalid")
}
err = repository.Collection.FindByID(*user, &res)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, res.Certificate, "")
assert.Equal(t, res.CertHash, "")
}
func ExampleAuth() {
mail := "example@example.example"
token := "example"
user := entities.NewUser()
user.Email = mail
user.RegToken = token
user.Csr = string(csr)
_, err = repository.Collection.Insert(*user)
if err != nil {
fmt.Println(err)
}
fmt.Println("User successfully inserted")
conn, err := net.Connect("localhost:9090", nil, nil, rootCA)
if err != nil {
fmt.Println("Unable to connect: ", err)
}
fmt.Println("Client successfully connected")
client := api.NewPlatformClient(conn)
request := &api.AuthRequest{Email: user.Email, Token: user.RegToken}
msg, err := client.Auth(context.Background(), request)
fmt.Println("AuthRequest successfully sent")
if msg == (*api.RegisteredUser)(nil) {
fmt.Println("The request should have been evaluated as valid")
}
if err != nil {
fmt.Println(err)
}
if msg.ClientCert == "" {
fmt.Println("The certificate should have been given as an answer")
}
fmt.Println("Certificate successfully recieved")
res := entities.User{}
err = repository.Collection.FindByID(*user, &res)
if err != nil {
fmt.Println(err)
}
if res.Certificate == "" || res.CertHash == "" {
fmt.Println("The database should have been updated")
}
fmt.Println("Database successfully updated with cert and certHash")
// Output:
// User successfully inserted
// Client successfully connected
// AuthRequest successfully sent
// Certificate successfully recieved
// Database successfully updated with cert and certHash
}
func TestRegisterTwice(t *testing.T) {
mail := "done@done.done"
user := entities.NewUser()
user.Email = mail
_, err = repository.Collection.Insert(*user)
if err != nil {
fmt.Println(err)
}
client := clientTest(t, ValidServ)
// An entry already exists with the same email
request := &api.RegisterRequest{Email: mail, Request: string(csr)}
errCode, err := client.Register(context.Background(), request)
assert.Equal(t, err, nil)
assert.Equal(t, errCode.Code, api.ErrorCode_INVARG)
}
func TestAuthTwice(t *testing.T) {
email := "email"
token := "token"
user := entities.NewUser()
user.Email = email
user.RegToken = token
user.Csr = string(csr)
user.Certificate = "foo"
user.CertHash = "foo"
_, err = repository.Collection.Insert(*user)
if err != nil {
t.Fatal(err)
}
// User is already registered
client := clientTest(t, ValidServ)
request := &api.AuthRequest{Email: email, Token: token}
msg, err := client.Auth(context.Background(), request)
assert.Equal(t, msg, (*api.RegisteredUser)(nil))
if err == nil {
t.Fatal("The user should have been evaluated as already registered")
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment