Skip to content

Commit

Permalink
Add rules for ACL (#306)
Browse files Browse the repository at this point in the history
Add rules HTTP endpoint for frontend - CRUD operations.
Add Default rule - allow all.
Send network map to peers based on rules.
  • Loading branch information
gigovich authored May 21, 2022
1 parent 11a3863 commit 3ce3ccc
Show file tree
Hide file tree
Showing 21 changed files with 1,194 additions and 187 deletions.
5 changes: 4 additions & 1 deletion client/cmd/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ func startManagement(t *testing.T, config *mgmt.Config) (*grpc.Server, net.Liste
}

peersUpdateManager := mgmt.NewPeersUpdateManager()
accountManager := mgmt.NewManager(store, peersUpdateManager, nil)
accountManager, err := mgmt.BuildManager(store, peersUpdateManager, nil)
if err != nil {
t.Fatal(err)
}
turnManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := mgmt.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion client/internal/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,10 @@ func startManagement(port int, dataDir string) (*grpc.Server, error) {
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
}
peersUpdateManager := server.NewPeersUpdateManager()
accountManager := server.NewManager(store, peersUpdateManager, nil)
accountManager, err := server.BuildManager(store, peersUpdateManager, nil)
if err != nil {
return nil, err
}
turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := server.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {
Expand Down
82 changes: 41 additions & 41 deletions management/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
const ValidKey = "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"

func startManagement(t *testing.T) (*grpc.Server, net.Listener) {

level, _ := log.ParseLevel("debug")
log.SetLevel(level)

Expand Down Expand Up @@ -56,7 +55,10 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
}

peersUpdateManager := mgmt.NewPeersUpdateManager()
accountManager := mgmt.NewManager(store, peersUpdateManager, nil)
accountManager, err := mgmt.BuildManager(store, peersUpdateManager, nil)
if err != nil {
t.Fatal(err)
}
turnManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
mgmtServer, err := mgmt.NewServer(config, accountManager, peersUpdateManager, turnManager)
if err != nil {
Expand Down Expand Up @@ -256,6 +258,7 @@ func TestClient_Sync(t *testing.T) {
}
if len(resp.GetRemotePeers()) != 1 {
t.Errorf("expecting RemotePeers size %d got %d", 1, len(resp.GetRemotePeers()))
return
}
if resp.GetRemotePeersIsEmpty() == true {
t.Error("expecting RemotePeers property to be false, got true")
Expand Down Expand Up @@ -295,37 +298,36 @@ func Test_SystemMetaDataFromClient(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)

mgmtMockServer.LoginFunc =
func(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
peerKey, err := wgtypes.ParseKey(msg.GetWgPubKey())
if err != nil {
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", msg.WgPubKey)
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", msg.WgPubKey)
}

loginReq := &proto.LoginRequest{}
err = encryption.DecryptMessage(peerKey, serverKey, msg.Body, loginReq)
if err != nil {
log.Fatal(err)
}
mgmtMockServer.LoginFunc = func(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
peerKey, err := wgtypes.ParseKey(msg.GetWgPubKey())
if err != nil {
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", msg.WgPubKey)
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", msg.WgPubKey)
}

actualMeta = loginReq.GetMeta()
actualValidKey = loginReq.GetSetupKey()
wg.Done()
loginReq := &proto.LoginRequest{}
err = encryption.DecryptMessage(peerKey, serverKey, msg.Body, loginReq)
if err != nil {
log.Fatal(err)
}

loginResp := &proto.LoginResponse{}
encryptedResp, err := encryption.EncryptMessage(peerKey, serverKey, loginResp)
if err != nil {
return nil, err
}
actualMeta = loginReq.GetMeta()
actualValidKey = loginReq.GetSetupKey()
wg.Done()

return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
loginResp := &proto.LoginResponse{}
encryptedResp, err := encryption.EncryptMessage(peerKey, serverKey, loginResp)
if err != nil {
return nil, err
}

return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
}

info := system.GetInfo()
_, err = testClient.Register(*key, ValidKey, "", info)
if err != nil {
Expand Down Expand Up @@ -370,21 +372,19 @@ func Test_GetDeviceAuthorizationFlow(t *testing.T) {
ProviderConfig: &proto.ProviderConfig{ClientID: "client"},
}

mgmtMockServer.GetDeviceAuthorizationFlowFunc =
func(ctx context.Context, req *mgmtProto.EncryptedMessage) (*proto.EncryptedMessage, error) {

encryptedResp, err := encryption.EncryptMessage(serverKey, client.key, expectedFlowInfo)
if err != nil {
return nil, err
}

return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
mgmtMockServer.GetDeviceAuthorizationFlowFunc = func(ctx context.Context, req *mgmtProto.EncryptedMessage) (*proto.EncryptedMessage, error) {
encryptedResp, err := encryption.EncryptMessage(serverKey, client.key, expectedFlowInfo)
if err != nil {
return nil, err
}

return &mgmtProto.EncryptedMessage{
WgPubKey: serverKey.PublicKey().String(),
Body: encryptedResp,
Version: 0,
}, nil
}

flowInfo, err := client.GetDeviceAuthorizationFlow(serverKey)
if err != nil {
t.Error("error while retrieving device auth flow information")
Expand Down
12 changes: 7 additions & 5 deletions management/cmd/management.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,23 @@ var (
}
}

accountManager := server.NewManager(store, peersUpdateManager, idpManager)
accountManager, err := server.BuildManager(store, peersUpdateManager, idpManager)
if err != nil {
log.Fatalln("failed build default manager: ", err)
}

var opts []grpc.ServerOption

var httpServer *http.Server
if config.HttpConfig.LetsEncryptDomain != "" {
//automatically generate a new certificate with Let's Encrypt
// automatically generate a new certificate with Let's Encrypt
certManager := encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
opts = append(opts, grpc.Creds(transportCredentials))

httpServer = http.NewHttpsServer(config.HttpConfig, certManager, accountManager)
} else if config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "" {
//use provided certificate
// use provided certificate
tlsConfig, err := loadTLSConfig(config.HttpConfig.CertFile, config.HttpConfig.CertKey)
if err != nil {
log.Fatal("cannot load TLS credentials: ", err)
Expand All @@ -130,7 +133,7 @@ var (
opts = append(opts, grpc.Creds(transportCredentials))
httpServer = http.NewHttpsServerWithTLSConfig(config.HttpConfig, tlsConfig, accountManager)
} else {
//start server without SSL
// start server without SSL
httpServer = http.NewHttpServer(config.HttpConfig, accountManager)
}

Expand Down Expand Up @@ -309,5 +312,4 @@ func init() {
mgmtCmd.Flags().StringVar(&certFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
mgmtCmd.Flags().StringVar(&certKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
rootCmd.MarkFlagRequired("config") //nolint

}
82 changes: 77 additions & 5 deletions management/server/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ const (
type AccountManager interface {
GetOrCreateAccountByUser(userId, domain string) (*Account, error)
GetAccountByUser(userId string) (*Account, error)
AddSetupKey(accountId string, keyName string, keyType SetupKeyType, expiresIn *util.Duration) (*SetupKey, error)
AddSetupKey(
accountId string,
keyName string,
keyType SetupKeyType,
expiresIn *util.Duration,
) (*SetupKey, error)
RevokeSetupKey(accountId string, keyId string) (*SetupKey, error)
RenameSetupKey(accountId string, keyId string, newName string) (*SetupKey, error)
GetAccountById(accountId string) (*Account, error)
Expand All @@ -47,6 +52,10 @@ type AccountManager interface {
GroupAddPeer(accountId, groupID, peerKey string) error
GroupDeletePeer(accountId, groupID, peerKey string) error
GroupListPeers(accountId, groupID string) ([]*Peer, error)
GetRule(accountId, ruleID string) (*Rule, error)
SaveRule(accountID string, rule *Rule) error
DeleteRule(accountId, ruleID string) error
ListRules(accountId string) ([]*Rule, error)
}

type DefaultAccountManager struct {
Expand All @@ -70,6 +79,7 @@ type Account struct {
Peers map[string]*Peer
Users map[string]*User
Groups map[string]*Group
Rules map[string]*Rule
}

type UserInfo struct {
Expand Down Expand Up @@ -101,24 +111,60 @@ func (a *Account) Copy() *Account {
setupKeys[id] = key.Copy()
}

groups := map[string]*Group{}
for id, group := range a.Groups {
groups[id] = group.Copy()
}

rules := map[string]*Rule{}
for id, rule := range a.Rules {
rules[id] = rule.Copy()
}

return &Account{
Id: a.Id,
CreatedBy: a.CreatedBy,
SetupKeys: setupKeys,
Network: a.Network.Copy(),
Peers: peers,
Users: users,
Groups: groups,
Rules: rules,
}
}

// NewManager creates a new DefaultAccountManager with a provided Store
func NewManager(store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager) *DefaultAccountManager {
return &DefaultAccountManager{
func (a *Account) GetGroupAll() (*Group, error) {
for _, g := range a.Groups {
if g.Name == "All" {
return g, nil
}
}
return nil, fmt.Errorf("no group ALL found")
}

// BuildManager creates a new DefaultAccountManager with a provided Store
func BuildManager(
store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager,
) (*DefaultAccountManager, error) {
dam := &DefaultAccountManager{
Store: store,
mux: sync.Mutex{},
peersUpdateManager: peersUpdateManager,
idpManager: idpManager,
}

// if account has not default account
// we build 'all' group and add all peers into it
// also we create default rule with source an destination
// groups 'all'
for _, account := range store.GetAllAccounts() {
dam.addAllGroup(account)
if err := store.SaveAccount(account); err != nil {
return nil, err
}
}

return dam, nil
}

// AddSetupKey generates a new setup key with a given name and type, and adds it to the specified account
Expand Down Expand Up @@ -223,7 +269,9 @@ func (am *DefaultAccountManager) GetAccountById(accountId string) (*Account, err

// GetAccountByUserOrAccountId look for an account by user or account Id, if no account is provided and
// user id doesn't have an account associated with it, one account is created
func (am *DefaultAccountManager) GetAccountByUserOrAccountId(userId, accountId, domain string) (*Account, error) {
func (am *DefaultAccountManager) GetAccountByUserOrAccountId(
userId, accountId, domain string,
) (*Account, error) {
if accountId != "" {
return am.GetAccountById(accountId)
} else if userId != "" {
Expand Down Expand Up @@ -490,6 +538,8 @@ func (am *DefaultAccountManager) AddAccount(accountId, userId, domain string) (*
func (am *DefaultAccountManager) createAccount(accountId, userId, domain string) (*Account, error) {
account := newAccountWithId(accountId, userId, domain)

am.addAllGroup(account)

err := am.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed creating account")
Expand All @@ -498,6 +548,28 @@ func (am *DefaultAccountManager) createAccount(accountId, userId, domain string)
return account, nil
}

// addAllGroup to account object it it doesn't exists
func (am *DefaultAccountManager) addAllGroup(account *Account) {
if len(account.Groups) == 0 {
allGroup := &Group{
ID: xid.New().String(),
Name: "All",
}
for _, peer := range account.Peers {
allGroup.Peers = append(allGroup.Peers, peer.Key)
}
account.Groups = map[string]*Group{allGroup.ID: allGroup}

defaultRule := &Rule{
ID: xid.New().String(),
Name: "Default",
Source: []string{allGroup.ID},
Destination: []string{allGroup.ID},
}
account.Rules = map[string]*Rule{defaultRule.ID: defaultRule}
}
}

// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
func newAccountWithId(accountId, userId, domain string) *Account {
log.Debugf("creating new account")
Expand Down
Loading

0 comments on commit 3ce3ccc

Please sign in to comment.