register.go 3.6 KB
Newer Older
1 2 3 4 5 6 7
package user

import (
	"errors"
	"regexp"
	"time"

Loïck Bonniot's avatar
Loïck Bonniot committed
8 9 10
	"dfss/dfssc/common"
	"dfss/dfssc/security"
	pb "dfss/dfssp/api"
11
	"dfss/net"
Loïck Bonniot's avatar
Loïck Bonniot committed
12
	"github.com/spf13/viper"
13
	"golang.org/x/net/context"
14
	"google.golang.org/grpc"
15 16 17 18
)

// RegisterManager handles the registration of a user
type RegisterManager struct {
ElyKar's avatar
ElyKar committed
19
	*viper.Viper
20 21 22 23 24 25 26 27
	passphrase   string
	country      string
	organization string
	unit         string
	mail         string
	bits         int
}

Loïck Bonniot's avatar
Loïck Bonniot committed
28 29
var mailRegex = regexp.MustCompile(`.+@.+\..+`)

30
// NewRegisterManager return a new Register Manager to register a user
ElyKar's avatar
ElyKar committed
31 32
func NewRegisterManager(passphrase, country, organization, unit, mail string, bits int, v *viper.Viper) (*RegisterManager, error) {
	m := &RegisterManager{v, passphrase, country, organization, unit, mail, bits}
33 34 35 36 37 38 39 40 41 42 43 44 45 46

	if err := m.checkValidParams(); err != nil {
		return nil, err
	}

	if err := m.checkFilePresence(); err != nil {
		return nil, err
	}

	return m, nil
}

// Check the validity of the provided email, passphrase and bits
func (m *RegisterManager) checkValidParams() error {
Loïck Bonniot's avatar
Loïck Bonniot committed
47
	if b := mailRegex.MatchString(m.mail); !b {
48 49 50 51 52 53 54 55 56 57 58 59 60 61
		return errors.New("Provided mail is not valid")
	}

	if m.bits != 2048 && m.bits != 4096 {
		return errors.New("Length of the key should be 2048 or 4096 bits")
	}

	return nil
}

// Check there is no private key nor client certificate
// Check the CA is present and valid
// Check there is not a duplicate file
func (m *RegisterManager) checkFilePresence() error {
ElyKar's avatar
ElyKar committed
62 63 64
	fileKey := m.GetString("file_key")
	if b := common.FileExists(fileKey); b {
		return errors.New("A private key is already present at path " + fileKey)
65 66
	}

ElyKar's avatar
ElyKar committed
67 68 69
	fileCert := m.GetString("file_cert")
	if b := common.FileExists(fileCert); b {
		return errors.New("A certificate is already present at path " + fileCert)
70 71
	}

ElyKar's avatar
ElyKar committed
72
	if fileKey == fileCert {
73 74 75
		return errors.New("Cannot store certificate and key in the same file")
	}

ElyKar's avatar
ElyKar committed
76 77 78
	fileCA := m.GetString("file_ca")
	if b := common.FileExists(fileCA); !b {
		return errors.New("You need the certificate of the platform at path " + fileCA)
79 80
	}

ElyKar's avatar
ElyKar committed
81
	data, err := security.GetCertificate(fileCA)
82 83 84 85 86 87 88 89 90 91 92 93 94
	if err != nil {
		return err
	}

	if time.Now().After(data.NotAfter) {
		return errors.New("Root certificate has expired")
	}

	return nil
}

// GetCertificate handles the creation of a certificate, delete private key upon failure
func (m *RegisterManager) GetCertificate() error {
ElyKar's avatar
ElyKar committed
95
	fileKey := m.GetString("file_key")
96 97
	request, err := m.buildCertificateRequest()
	if err != nil {
ElyKar's avatar
ElyKar committed
98
		common.DeleteQuietly(fileKey)
99 100 101 102 103
		return err
	}

	code, err := m.sendRequest(request)
	if err != nil {
ElyKar's avatar
ElyKar committed
104
		common.DeleteQuietly(fileKey)
105 106 107
		return err
	}

Loïck Bonniot's avatar
Loïck Bonniot committed
108
	err = common.EvaluateErrorCodeResponse(code)
109
	if err != nil {
ElyKar's avatar
ElyKar committed
110
		common.DeleteQuietly(fileKey)
111 112 113 114 115 116 117 118
		return err
	}

	return nil
}

// Builds a certificate request
func (m *RegisterManager) buildCertificateRequest() (string, error) {
ElyKar's avatar
ElyKar committed
119
	key, err := security.GenerateKeys(m.bits, m.passphrase)
120 121 122 123 124 125 126 127 128 129 130 131 132 133
	if err != nil {
		return "", err
	}

	request, err := security.GenerateCertificateRequest(m.country, m.organization, m.unit, m.mail, key)
	if err != nil {
		return "", err
	}

	return request, nil
}

// Send the request and returns the response
func (m *RegisterManager) sendRequest(certRequest string) (*pb.ErrorCode, error) {
ElyKar's avatar
ElyKar committed
134
	client, err := connect()
135 136 137 138 139 140 141 142 143 144 145
	if err != nil {
		return nil, err
	}

	// gRPC request
	request := &pb.RegisterRequest{
		Email:   m.mail,
		Request: certRequest,
	}

	// Stop the context if it takes too long for the platform to answer
146
	ctx, cancel := context.WithTimeout(context.Background(), net.DefaultTimeout)
147 148 149
	defer cancel()
	response, err := client.Register(ctx, request)
	if err != nil {
150
		return nil, errors.New(grpc.ErrorDesc(err))
151 152 153 154
	}

	return response, nil
}