Compare commits

...

11 Commits

Author SHA1 Message Date
Mikhail Bragin
e3b809a1d4 Update ManagementURL in Config (#262)
If ManagementURL is present in the config file
and cmd (e.g. up or login) specifies a new one,
then update config file with a new ManagementURL
2022-03-13 15:17:18 +01:00
Mikhail Bragin
b2f4322a31 Set local unix socket permissions to rw (#263) 2022-03-13 15:16:35 +01:00
Mikhail Bragin
d7b69b91b9 Fix error when removing peer conn (#264)
When stopping engine, all peer conns have to be closed
and for each peer WireGuard iface is called
to remove WireGuard peer.
This operation happens in a goroutine causing
Engine to remove the whole WireGuard interface before.
Therefore consequent calls to RemovePeer are unsuccessful.
This fix just adds a small delay before removing interface.
2022-03-13 15:16:16 +01:00
Mikhail Bragin
a3a6283ac6 Update windows installer and docs
Update binary installation docs
Add service start in Windows installer
2022-03-11 14:05:44 +01:00
Mikhail Bragin
be0c5c887c Persist Network Serial to Store to avoid outdated netmap sent (#260)
Fix outdated update coming from management
even when it is actually not outdated.
2022-03-10 18:18:38 +01:00
Mikhail Bragin
8cc93e0dbe Init logger for every cmd (#259) 2022-03-10 18:14:07 +01:00
Maycon Santos
24d5f9efac Enable Report Caller when log level Debug (#258)
Enabling report caller when log level equals debug
Also added a Caller prettyfier
to avoid full file path
2022-03-10 14:14:00 +01:00
Maycon Santos
c1b162c974 Improve private domain's behavior tests and logic (#256)
Improved the behavior tests for private domains
and its logic as well because on existing accounts
there was no primary status update
2022-03-10 13:47:36 +01:00
Maycon Santos
612ef98f03 Call start services function for tests (#257)
* Call start services function for tests

when testing CMDs we were using some global
variables which got replaced by parallel test

Now we will call a single function independently
for each test
2022-03-10 11:53:09 +01:00
Maycon Santos
605ca03519 Fix IDP Manager config structs with correct tags (#253)
* Fix IDP Manager config structs with correct tags

When loading the configuration from file
we will use the Auth0ClientConfig and when
sending the post to retrieve a token
 we use the auth0JWTRequest with proper tags

 Also, removed the idle timeout as it was closing
 all idle connections
2022-03-09 17:22:47 +01:00
Maycon Santos
ff62fec956 Handle category change with provided Acc Id (#252)
When account id supplied via claim, we should
handle change of the domain classification.

If category of domain change to private, we
should re-evaluate the private account
2022-03-09 13:31:42 +01:00
29 changed files with 387 additions and 152 deletions

View File

@@ -126,7 +126,7 @@ Hosted version:
```shell
brew install wiretrustee/client/wiretrustee
```
**Installation from binary**
**Installation from binary**
1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest)
2. Download the latest release (**Switch VERSION to the latest**):
```shell
@@ -138,10 +138,15 @@ Hosted version:
sudo mv wiretrusee /usr/local/bin/wiretrustee
chmod +x /usr/local/bin/wiretrustee
```
After that you may need to add /usr/local/bin in your MAC's PATH environment variable:
After that you may need to add /usr/local/bin in your PATH environment variable:
````shell
export PATH=$PATH:/usr/local/bin
````
4. Install and run the service
```shell
sudo wiretrustee service install
sudo wiretrustee service start
```
#### Windows
1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest)
@@ -192,6 +197,21 @@ For **Windows** systems:
3. Repeat on other machines.
### Troubleshooting
1. If you have specified a wrong `--management-url` (e.g., just by mistake when self-hosting)
to override it you can do the following:
```shell
sudo wiretrustee down
sudo wiretrustee up --management-url https://<CORRECT HOST:PORT>/
```
2. If you are using self-hosted version and haven't specified `--management-url`, the client app will use the default URL
which is ```https://api.wiretrustee.com:33073```.
To override it see solution #1 above.
### Running Dashboard, Management, Signal and Coturn
See [Self-Hosting Guide](https://docs.wiretrustee.com/getting-started/self-hosting)

View File

@@ -2,6 +2,7 @@ package cmd
import (
"context"
"github.com/wiretrustee/wiretrustee/util"
"time"
log "github.com/sirupsen/logrus"
@@ -16,6 +17,12 @@ var downCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

View File

@@ -3,6 +3,7 @@ package cmd
import (
"context"
"fmt"
"github.com/wiretrustee/wiretrustee/util"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -16,6 +17,13 @@ var loginCmd = &cobra.Command{
Short: "login to the Wiretrustee Management Service (first run)",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
ctx := internal.CtxInitState(context.Background())
// workaround to run without service

View File

@@ -2,35 +2,17 @@ package cmd
import (
"fmt"
"path/filepath"
"strings"
"testing"
"github.com/wiretrustee/wiretrustee/client/internal"
"github.com/wiretrustee/wiretrustee/iface"
mgmt "github.com/wiretrustee/wiretrustee/management/server"
"github.com/wiretrustee/wiretrustee/util"
)
var mgmAddr string
func TestLogin_Start(t *testing.T) {
config := &mgmt.Config{}
_, err := util.ReadJson("../testdata/management.json", config)
if err != nil {
t.Fatal(err)
}
testDir := t.TempDir()
config.Datadir = testDir
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
if err != nil {
t.Fatal(err)
}
_, listener := startManagement(t, config)
mgmAddr = listener.Addr().String()
}
func TestLogin(t *testing.T) {
mgmAddr := startTestingServices(t)
tempDir := t.TempDir()
confPath := tempDir + "/config.json"
mgmtURL := fmt.Sprintf("http://%s", mgmAddr)

View File

@@ -45,6 +45,14 @@ func (p *program) Start(svc service.Service) error {
}
defer listen.Close()
if split[0] == "unix" {
err = os.Chmod(split[1], 0666)
if err != nil {
log.Errorf("failed setting daemon permissions: %v", split[1])
return
}
}
serverInstance := server.New(p.ctx, managementURL, configPath, stopCh, cleanupCh)
if err := serverInstance.Start(); err != nil {
log.Fatalf("failed start daemon: %v", err)

View File

@@ -2,6 +2,7 @@ package cmd
import (
"context"
"github.com/wiretrustee/wiretrustee/util"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -16,6 +17,13 @@ var statusCmd = &cobra.Command{
Short: "status of the Wiretrustee Service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
ctx := internal.CtxInitState(context.Background())
conn, err := DialClientGRPCServer(ctx, daemonAddr)

View File

@@ -2,7 +2,9 @@ package cmd
import (
"context"
"github.com/wiretrustee/wiretrustee/util"
"net"
"path/filepath"
"testing"
"time"
@@ -15,6 +17,28 @@ import (
"google.golang.org/grpc"
)
func startTestingServices(t *testing.T) string {
config := &mgmt.Config{}
_, err := util.ReadJson("../testdata/management.json", config)
if err != nil {
t.Fatal(err)
}
testDir := t.TempDir()
config.Datadir = testDir
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
if err != nil {
t.Fatal(err)
}
_, signalLis := startSignal(t)
signalAddr := signalLis.Addr().String()
config.Signal.URI = signalAddr
_, mgmLis := startManagement(t, config)
mgmAddr := mgmLis.Addr().String()
return mgmAddr
}
func startSignal(t *testing.T) (*grpc.Server, net.Listener) {
lis, err := net.Listen("tcp", ":0")
if err != nil {

View File

@@ -3,6 +3,7 @@ package cmd
import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/wiretrustee/wiretrustee/util"
"github.com/wiretrustee/wiretrustee/client/internal"
"github.com/wiretrustee/wiretrustee/client/proto"
@@ -13,6 +14,13 @@ var upCmd = &cobra.Command{
Short: "install, login and start wiretrustee client",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
err := util.InitLog(logLevel, logFile)
if err != nil {
log.Errorf("failed initializing log %v", err)
return err
}
ctx := internal.CtxInitState(cmd.Context())
// workaround to run without service

View File

@@ -2,37 +2,15 @@ package cmd
import (
"context"
"path/filepath"
"testing"
"time"
"github.com/wiretrustee/wiretrustee/client/internal"
mgmt "github.com/wiretrustee/wiretrustee/management/server"
"github.com/wiretrustee/wiretrustee/util"
)
func TestUpDaemon_Start(t *testing.T) {
config := &mgmt.Config{}
_, err := util.ReadJson("../testdata/management.json", config)
if err != nil {
t.Fatal(err)
}
testDir := t.TempDir()
config.Datadir = testDir
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
if err != nil {
t.Fatal(err)
}
_, signalLis := startSignal(t)
signalAddr = signalLis.Addr().String()
config.Signal.URI = signalAddr
_, mgmLis := startManagement(t, config)
mgmAddr = mgmLis.Addr().String()
}
func TestUpDaemon(t *testing.T) {
mgmAddr := startTestingServices(t)
tempDir := t.TempDir()
confPath := tempDir + "/config.json"

View File

@@ -2,42 +2,20 @@ package cmd
import (
"net/url"
"path/filepath"
"testing"
"time"
"github.com/wiretrustee/wiretrustee/iface"
mgmt "github.com/wiretrustee/wiretrustee/management/server"
"github.com/wiretrustee/wiretrustee/util"
)
var (
signalAddr string
cliAddr string
//signalAddr string
cliAddr string
)
func TestUp_Start(t *testing.T) {
config := &mgmt.Config{}
_, err := util.ReadJson("../testdata/management.json", config)
if err != nil {
t.Fatal(err)
}
testDir := t.TempDir()
config.Datadir = testDir
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
if err != nil {
t.Fatal(err)
}
_, signalLis := startSignal(t)
signalAddr = signalLis.Addr().String()
config.Signal.URI = signalAddr
_, mgmLis := startManagement(t, config)
mgmAddr = mgmLis.Addr().String()
}
func TestUp(t *testing.T) {
mgmAddr := startTestingServices(t)
tempDir := t.TempDir()
confPath := tempDir + "/config.json"
mgmtURL, err := url.Parse("http://" + mgmAddr)
@@ -66,7 +44,7 @@ func TestUp(t *testing.T) {
}()
time.Sleep(time.Second * 2)
timeout := 15 * time.Second
timeout := 30 * time.Second
timeoutChannel := time.After(timeout)
for {
select {

View File

@@ -97,6 +97,7 @@ EnVar::SetHKLM
EnVar::AddValueEx "path" "$INSTDIR"
Exec '"$INSTDIR\${MAIN_APP_EXE}" service install'
Exec '"$INSTDIR\${MAIN_APP_EXE}" service start'
# sleep a bit for visibility
Sleep 1000
SectionEnd

View File

@@ -86,12 +86,18 @@ func ReadConfig(managementURL string, configPath string) (*Config, error) {
return nil, err
}
if managementURL != "" {
if managementURL != "" && config.ManagementURL.String() != managementURL {
URL, err := parseManagementURL(managementURL)
if err != nil {
return nil, err
}
config.ManagementURL = URL
// since we have new management URL, we need to update config file
err = util.WriteJson(configPath, config)
if err != nil {
return nil, err
}
log.Infof("new Management URL provided, updated to %s (old value %s)", managementURL, config.ManagementURL)
}
return config, err

View File

@@ -0,0 +1,60 @@
package internal
import (
"errors"
"github.com/stretchr/testify/assert"
"github.com/wiretrustee/wiretrustee/util"
"os"
"path/filepath"
"testing"
)
func TestReadConfig(t *testing.T) {
}
func TestGetConfig(t *testing.T) {
managementURL := "https://test.management.url:33071"
path := filepath.Join(t.TempDir(), "config.json")
preSharedKey := "preSharedKey"
// case 1: new config has to be generated
config, err := GetConfig(managementURL, path, preSharedKey)
if err != nil {
return
}
assert.Equal(t, config.ManagementURL.String(), managementURL)
assert.Equal(t, config.PreSharedKey, preSharedKey)
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
t.Errorf("config file was expected to be created under path %s", path)
}
// case 2: existing config -> fetch it
config, err = GetConfig(managementURL, path, preSharedKey)
if err != nil {
return
}
assert.Equal(t, config.ManagementURL.String(), managementURL)
assert.Equal(t, config.PreSharedKey, preSharedKey)
// case 3: existing config, but new managementURL has been provided -> update config
newManagementURL := "https://test.newManagement.url:33071"
config, err = GetConfig(newManagementURL, path, preSharedKey)
if err != nil {
return
}
assert.Equal(t, config.ManagementURL.String(), newManagementURL)
assert.Equal(t, config.PreSharedKey, preSharedKey)
// read once more to make sure that config file has been updated with the new management URL
readConf, err := util.ReadJson(path, config)
if err != nil {
return
}
assert.Equal(t, readConf.(*Config).ManagementURL.String(), newManagementURL)
}

View File

@@ -85,7 +85,7 @@ type Engine struct {
udpMuxConn *net.UDPConn
udpMuxConnSrflx *net.UDPConn
// networkSerial is the latest Serial (state ID) of the network sent by the Management service
// networkSerial is the latest CurrentSerial (state ID) of the network sent by the Management service
networkSerial uint64
}
@@ -123,6 +123,10 @@ func (e *Engine) Stop() error {
return err
}
// very ugly but we want to remove peers from the WireGuard interface first before removing interface.
// Removing peers happens in the conn.CLose() asynchronously
time.Sleep(500 * time.Millisecond)
log.Debugf("removing Wiretrustee interface %s", e.config.WgIfaceName)
if e.wgInterface.Interface != nil {
err = e.wgInterface.Close()
@@ -489,7 +493,7 @@ func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
// if peer has been removed -> give up
if !e.peerExists(peerKey) {
log.Infof("peer %s doesn't exist anymore, won't retry connection", peerKey)
log.Debugf("peer %s doesn't exist anymore, won't retry connection", peerKey)
return
}

View File

@@ -96,7 +96,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
expectedSerial: 1,
}
// 2nd case - one extra peer added and network map has Serial grater than local => apply the update
// 2nd case - one extra peer added and network map has CurrentSerial grater than local => apply the update
case2 := testCase{
name: "input with an old peer and a new peer to add",
networkMap: &mgmtProto.NetworkMap{

View File

@@ -153,7 +153,7 @@ func (conn *Conn) Open() error {
defer func() {
err := conn.cleanup()
if err != nil {
log.Errorf("error while cleaning up peer connection %s: %v", conn.config.Key, err)
log.Warnf("error while cleaning up peer connection %s: %v", conn.config.Key, err)
return
}
}()

View File

@@ -64,6 +64,7 @@ func (s *Server) Start() error {
log.Warnf("no config file, skip connection stage: %v", err)
return nil
}
s.config = config
go func() {
if err := internal.RunClient(ctx, config, s.stopCh, s.cleanupCh); err != nil {

View File

@@ -836,7 +836,7 @@ type NetworkMap struct {
// Serial is an ID of the network state to be used by clients to order updates.
// The larger the Serial the newer the configuration.
// E.g. the client app should keep track of this id locally and discard all the configurations with a lower value
Serial uint64 `protobuf:"varint,1,opt,name=Serial,proto3" json:"Serial,omitempty"`
Serial uint64 `protobuf:"varint,1,opt,name=CurrentSerial,proto3" json:"CurrentSerial,omitempty"`
// PeerConfig represents configuration of a peer
PeerConfig *PeerConfig `protobuf:"bytes,2,opt,name=peerConfig,proto3" json:"peerConfig,omitempty"`
// RemotePeerConfig represents a list of remote peers that the receiver can connect to

View File

@@ -248,11 +248,16 @@ func (am *DefaultAccountManager) updateAccountDomainAttributes(account *Account,
func (am *DefaultAccountManager) handleExistingUserAccount(existingAcc *Account, domainAcc *Account, claims jwtclaims.AuthorizationClaims) error {
var err error
if domainAcc == nil || existingAcc.Id != domainAcc.Id {
if domainAcc != nil && existingAcc.Id != domainAcc.Id {
err = am.updateAccountDomainAttributes(existingAcc, claims, false)
if err != nil {
return err
}
} else {
err = am.updateAccountDomainAttributes(existingAcc, claims, true)
if err != nil {
return err
}
}
// we should register the account ID to this user's metadata in our IDP manager
@@ -268,24 +273,21 @@ func (am *DefaultAccountManager) handleExistingUserAccount(existingAcc *Account,
// otherwise it will create a new account and make it primary account for the domain.
func (am *DefaultAccountManager) handleNewUserAccount(domainAcc *Account, claims jwtclaims.AuthorizationClaims) (*Account, error) {
var (
account *Account
primaryAccount bool
account *Account
err error
)
lowerDomain := strings.ToLower(claims.Domain)
// if domain already has a primary account, add regular user
if domainAcc != nil {
account = domainAcc
account.Users[claims.UserId] = NewRegularUser(claims.UserId)
primaryAccount = false
} else {
account = NewAccount(claims.UserId, lowerDomain)
account.Users[claims.UserId] = NewAdminUser(claims.UserId)
primaryAccount = true
}
err := am.updateAccountDomainAttributes(account, claims, primaryAccount)
if err != nil {
return nil, err
err = am.updateAccountDomainAttributes(account, claims, true)
if err != nil {
return nil, err
}
}
err = am.updateIDPMetadata(claims.UserId, account.Id)
@@ -316,8 +318,16 @@ func (am *DefaultAccountManager) handleNewUserAccount(domainAcc *Account, claims
func (am *DefaultAccountManager) GetAccountWithAuthorizationClaims(claims jwtclaims.AuthorizationClaims) (*Account, error) {
// if Account ID is part of the claims
// it means that we've already classified the domain and user has an account
if claims.DomainCategory != PrivateCategory || claims.AccountId != "" {
if claims.DomainCategory != PrivateCategory {
return am.GetAccountByUserOrAccountId(claims.UserId, claims.AccountId, claims.Domain)
} else if claims.AccountId != "" {
accountFromID, err := am.GetAccountByUserOrAccountId(claims.UserId, claims.AccountId, claims.Domain)
if err != nil {
return nil, err
}
if accountFromID.DomainCategory == PrivateCategory || claims.DomainCategory != PrivateCategory {
return accountFromID, nil
}
}
am.mux.Lock()

View File

@@ -39,13 +39,16 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
type initUserParams jwtclaims.AuthorizationClaims
type test struct {
name string
inputClaims jwtclaims.AuthorizationClaims
inputInitUserParams initUserParams
inputUpdateAttrs bool
testingFunc require.ComparisonAssertionFunc
expectedMSG string
expectedUserRole UserRole
name string
inputClaims jwtclaims.AuthorizationClaims
inputInitUserParams initUserParams
inputUpdateAttrs bool
inputUpdateClaimAccount bool
testingFunc require.ComparisonAssertionFunc
expectedMSG string
expectedUserRole UserRole
expectedDomainCategory string
expectedPrimaryDomainStatus bool
}
var (
@@ -66,10 +69,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
UserId: "pub-domain-user",
DomainCategory: PublicCategory,
},
inputInitUserParams: defaultInitAccount,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
inputInitUserParams: defaultInitAccount,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
expectedDomainCategory: "",
expectedPrimaryDomainStatus: false,
}
initUnknown := defaultInitAccount
@@ -83,10 +88,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
UserId: "unknown-domain-user",
DomainCategory: UnknownCategory,
},
inputInitUserParams: initUnknown,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
inputInitUserParams: initUnknown,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
expectedDomainCategory: "",
expectedPrimaryDomainStatus: false,
}
testCase3 := test{
@@ -96,10 +103,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
UserId: "pvt-domain-user",
DomainCategory: PrivateCategory,
},
inputInitUserParams: defaultInitAccount,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
inputInitUserParams: defaultInitAccount,
testingFunc: require.NotEqual,
expectedMSG: "account IDs shouldn't match",
expectedUserRole: UserRoleAdmin,
expectedDomainCategory: PrivateCategory,
expectedPrimaryDomainStatus: true,
}
privateInitAccount := defaultInitAccount
@@ -113,11 +122,13 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
UserId: "pvt-domain-user",
DomainCategory: PrivateCategory,
},
inputUpdateAttrs: true,
inputInitUserParams: privateInitAccount,
testingFunc: require.Equal,
expectedMSG: "account IDs should match",
expectedUserRole: UserRoleUser,
inputUpdateAttrs: true,
inputInitUserParams: privateInitAccount,
testingFunc: require.Equal,
expectedMSG: "account IDs should match",
expectedUserRole: UserRoleUser,
expectedDomainCategory: PrivateCategory,
expectedPrimaryDomainStatus: true,
}
testCase5 := test{
@@ -127,13 +138,30 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
UserId: defaultInitAccount.UserId,
DomainCategory: PrivateCategory,
},
inputInitUserParams: defaultInitAccount,
testingFunc: require.Equal,
expectedMSG: "account IDs should match",
expectedUserRole: UserRoleAdmin,
inputInitUserParams: defaultInitAccount,
testingFunc: require.Equal,
expectedMSG: "account IDs should match",
expectedUserRole: UserRoleAdmin,
expectedDomainCategory: PrivateCategory,
expectedPrimaryDomainStatus: true,
}
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4, testCase5} {
testCase6 := test{
name: "Existing Account Id With Existing Reclassified Private Domain",
inputClaims: jwtclaims.AuthorizationClaims{
Domain: defaultInitAccount.Domain,
UserId: defaultInitAccount.UserId,
DomainCategory: PrivateCategory,
},
inputUpdateClaimAccount: true,
inputInitUserParams: defaultInitAccount,
testingFunc: require.Equal,
expectedMSG: "account IDs should match",
expectedUserRole: UserRoleAdmin,
expectedDomainCategory: PrivateCategory,
expectedPrimaryDomainStatus: true,
}
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4, testCase5, testCase6} {
t.Run(testCase.name, func(t *testing.T) {
manager, err := createManager(t)
@@ -147,12 +175,18 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
require.NoError(t, err, "update init user failed")
}
if testCase.inputUpdateClaimAccount {
testCase.inputClaims.AccountId = initAccount.Id
}
account, err := manager.GetAccountWithAuthorizationClaims(testCase.inputClaims)
require.NoError(t, err, "support function failed")
testCase.testingFunc(t, initAccount.Id, account.Id, testCase.expectedMSG)
require.EqualValues(t, testCase.expectedUserRole, account.Users[testCase.inputClaims.UserId].Role, "user role should match")
require.EqualValues(t, testCase.expectedUserRole, account.Users[testCase.inputClaims.UserId].Role, "expected user role should match")
require.EqualValues(t, testCase.expectedDomainCategory, account.DomainCategory, "expected account domain category should match")
require.EqualValues(t, testCase.expectedPrimaryDomainStatus, account.IsDomainPrimaryAccount, "expected account primary status should match")
})
}
}
@@ -363,7 +397,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
t.Fatal(err)
}
serial := account.Network.Serial() //should be 0
serial := account.Network.CurrentSerial() //should be 0
var setupKey *SetupKey
for _, key := range account.SetupKeys {
@@ -375,8 +409,8 @@ func TestAccountManager_AddPeer(t *testing.T) {
return
}
if account.Network.serial != 0 {
t.Errorf("expecting account network to have an initial serial=0")
if account.Network.Serial != 0 {
t.Errorf("expecting account network to have an initial Serial=0")
return
}
@@ -412,8 +446,8 @@ func TestAccountManager_AddPeer(t *testing.T) {
t.Errorf("expecting just added peer to have IP = %s, got %s", expectedPeerIP, peer.IP.String())
}
if account.Network.Serial() != 1 {
t.Errorf("expecting Network serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.Serial())
if account.Network.CurrentSerial() != 1 {
t.Errorf("expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.CurrentSerial())
}
}
@@ -464,8 +498,8 @@ func TestAccountManager_DeletePeer(t *testing.T) {
return
}
if account.Network.Serial() != 2 {
t.Errorf("expecting Network serial=%d to be incremented and be equal to 2 after adding and deleteing a peer", account.Network.Serial())
if account.Network.CurrentSerial() != 2 {
t.Errorf("expecting Network Serial=%d to be incremented and be equal to 2 after adding and deleteing a peer", account.Network.CurrentSerial())
}
}

View File

@@ -173,7 +173,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
peersToSend = append(peersToSend, p)
}
}
update := toSyncResponse(s.config, peer, peersToSend, nil, networkMap.Network.Serial())
update := toSyncResponse(s.config, peer, peersToSend, nil, networkMap.Network.CurrentSerial())
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
if err != nil {
// todo rethink if we should keep this return
@@ -362,7 +362,7 @@ func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.Mana
} else {
turnCredentials = nil
}
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.Serial())
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.CurrentSerial())
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
if err != nil {

View File

@@ -23,9 +23,18 @@ type Auth0Manager struct {
// Auth0ClientConfig auth0 manager client configurations
type Auth0ClientConfig struct {
Audience string `json:"audiance"`
Audience string
AuthIssuer string
ClientID string
ClientSecret string
GrantType string
}
// auth0JWTRequest payload struct to request a JWT Token
type auth0JWTRequest struct {
Audience string `json:"audience"`
AuthIssuer string `json:"auth_issuer"`
ClientId string `json:"client_id"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
}
@@ -40,11 +49,10 @@ type Auth0Credentials struct {
}
// NewAuth0Manager creates a new instance of the Auth0Manager
func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
func NewAuth0Manager(config Auth0ClientConfig) (*Auth0Manager, error) {
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
httpTransport.MaxIdleConns = 5
httpTransport.IdleConnTimeout = 30
httpClient := &http.Client{
Timeout: 10 * time.Second,
@@ -53,6 +61,18 @@ func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
helper := JsonParser{}
if config.ClientID == "" || config.ClientSecret == "" || config.GrantType == "" || config.Audience == "" || config.AuthIssuer == "" {
return nil, fmt.Errorf("auth0 idp configuration is not complete")
}
if config.GrantType != "client_credentials" {
return nil, fmt.Errorf("auth0 idp configuration failed. Grant Type should be client_credentials")
}
if !strings.HasPrefix(strings.ToLower(config.AuthIssuer), "https://") {
return nil, fmt.Errorf("auth0 idp configuration failed. AuthIssuer should contain https://")
}
credentials := &Auth0Credentials{
clientConfig: config,
httpClient: httpClient,
@@ -63,7 +83,7 @@ func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
credentials: credentials,
httpClient: httpClient,
helper: helper,
}
}, nil
}
// jwtStillValid returns true if the token still valid and have enough time to be used and get a response from Auth0
@@ -76,7 +96,7 @@ func (c *Auth0Credentials) requestJWTToken() (*http.Response, error) {
var res *http.Response
url := c.clientConfig.AuthIssuer + "/oauth/token"
p, err := c.helper.Marshal(c.clientConfig)
p, err := c.helper.Marshal(auth0JWTRequest(c.clientConfig))
if err != nil {
return res, err
}
@@ -89,6 +109,8 @@ func (c *Auth0Credentials) requestJWTToken() (*http.Response, error) {
req.Header.Add("content-type", "application/json")
log.Debug("requesting new jwt token for idp manager")
res, err = c.httpClient.Do(req)
if err != nil {
return res, err
@@ -187,6 +209,8 @@ func (am *Auth0Manager) UpdateUserAppMetadata(userId string, appMetadata AppMeta
req.Header.Add("authorization", "Bearer "+jwtToken.AccessToken)
req.Header.Add("content-type", "application/json")
log.Debugf("updating metadata for user %s", userId)
res, err := am.httpClient.Do(req)
if err != nil {
return err

View File

@@ -3,6 +3,7 @@ package idp
import (
"encoding/json"
"fmt"
"github.com/stretchr/testify/require"
"io/ioutil"
"net/http"
"strings"
@@ -402,3 +403,64 @@ func TestAuth0_UpdateUserAppMetadata(t *testing.T) {
})
}
}
func TestNewAuth0Manager(t *testing.T) {
type test struct {
name string
inputConfig Auth0ClientConfig
assertErrFunc require.ErrorAssertionFunc
assertErrFuncMessage string
}
defaultTestConfig := Auth0ClientConfig{
AuthIssuer: "https://abc-auth0.eu.auth0.com",
Audience: "https://abc-auth0.eu.auth0.com/api/v2/",
ClientID: "abcdefg",
ClientSecret: "supersecret",
GrantType: "client_credentials",
}
testCase1 := test{
name: "Good Scenario With Config",
inputConfig: defaultTestConfig,
assertErrFunc: require.NoError,
assertErrFuncMessage: "shouldn't return error",
}
testCase2Config := defaultTestConfig
testCase2Config.ClientID = ""
testCase2 := test{
name: "Missing Configuration",
inputConfig: testCase2Config,
assertErrFunc: require.Error,
assertErrFuncMessage: "shouldn't return error when field empty",
}
testCase3Config := defaultTestConfig
testCase3Config.AuthIssuer = "abc-auth0.eu.auth0.com"
testCase3 := test{
name: "Wrong Auth Issuer Format",
inputConfig: testCase3Config,
assertErrFunc: require.Error,
assertErrFuncMessage: "should return error when wrong auth issuer format",
}
testCase4Config := defaultTestConfig
testCase4Config.GrantType = "spa"
testCase4 := test{
name: "Wrong Grant Type",
inputConfig: testCase4Config,
assertErrFunc: require.Error,
assertErrFuncMessage: "should return error when wrong grant type",
}
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4} {
t.Run(testCase.name, func(t *testing.T) {
_, err := NewAuth0Manager(testCase.inputConfig)
testCase.assertErrFunc(t, err, testCase.assertErrFuncMessage)
})
}
}

View File

@@ -56,7 +56,7 @@ func NewManager(config Config) (Manager, error) {
case "none", "":
return nil, nil
case "auth0":
return NewAuth0Manager(config.Auth0ClientCredentials), nil
return NewAuth0Manager(config.Auth0ClientCredentials)
default:
return nil, fmt.Errorf("invalid manager type: %s", config.ManagerType)
}

View File

@@ -258,7 +258,7 @@ func Test_SyncProtocol(t *testing.T) {
}
if networkMap.GetSerial() <= 0 {
t.Fatalf("expecting SyncResponse to have NetworkMap with a positive Network Serial, actual %d", networkMap.GetSerial())
t.Fatalf("expecting SyncResponse to have NetworkMap with a positive Network CurrentSerial, actual %d", networkMap.GetSerial())
}
}

View File

@@ -22,34 +22,34 @@ type Network struct {
Id string
Net net.IPNet
Dns string
// serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
// Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
// Used to synchronize state to the client apps.
serial uint64
Serial uint64
mu sync.Mutex `json:"-"`
}
// NewNetwork creates a new Network initializing it with a serial=0
// NewNetwork creates a new Network initializing it with a Serial=0
func NewNetwork() *Network {
return &Network{
Id: xid.New().String(),
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
Dns: "",
serial: 0}
Serial: 0}
}
// IncSerial increments serial by 1 reflecting that the network state has been changed
// IncSerial increments Serial by 1 reflecting that the network state has been changed
func (n *Network) IncSerial() {
n.mu.Lock()
defer n.mu.Unlock()
n.serial = n.serial + 1
n.Serial = n.Serial + 1
}
// Serial returns the Network.serial of the network (latest state id)
func (n *Network) Serial() uint64 {
// CurrentSerial returns the Network.Serial of the network (latest state id)
func (n *Network) CurrentSerial() uint64 {
n.mu.Lock()
defer n.mu.Unlock()
return n.serial
return n.Serial
}
func (n *Network) Copy() *Network {
@@ -57,7 +57,7 @@ func (n *Network) Copy() *Network {
Id: n.Id,
Net: n.Net,
Dns: n.Dns,
serial: n.serial,
Serial: n.Serial,
}
}

View File

@@ -142,7 +142,7 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
RemotePeersIsEmpty: true,
// new field
NetworkMap: &proto.NetworkMap{
Serial: account.Network.Serial(),
Serial: account.Network.CurrentSerial(),
RemotePeers: []*proto.RemotePeerConfig{},
RemotePeersIsEmpty: true,
},
@@ -173,7 +173,7 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
RemotePeersIsEmpty: len(update) == 0,
// new field
NetworkMap: &proto.NetworkMap{
Serial: account.Network.Serial(),
Serial: account.Network.CurrentSerial(),
RemotePeers: update,
RemotePeersIsEmpty: len(update) == 0,
},

View File

@@ -35,11 +35,11 @@
"AuthKeysLocation": "<PASTE YOUR AUTH0 PUBLIC JWT KEYS LOCATION HERE>"
},
"IdpManagerConfig": {
"Manager": "<none|auth0>",
"ManagerType": "<none|auth0>",
"Auth0ClientCredentials": {
"Audience": "<PASTE YOUR AUTH0 AUDIENCE HERE>",
"AuthIssuer": "<PASTE YOUR AUTH0 Auth Issuer HERE>",
"ClientId": "<PASTE YOUR AUTH0 Application Client ID HERE>",
"AuthIssuer": "https://<PASTE YOUR AUTH0 Auth Issuer HERE>",
"ClientID": "<PASTE YOUR AUTH0 Application Client ID HERE>",
"ClientSecret": "<PASTE YOUR AUTH0 Application Client Secret HERE>",
"GrantType": "client_credentials"
}

View File

@@ -4,7 +4,10 @@ import (
log "github.com/sirupsen/logrus"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"path"
"path/filepath"
"runtime"
"strconv"
"time"
)
@@ -31,6 +34,15 @@ func InitLog(logLevel string, logPath string) error {
logFormatter := new(log.TextFormatter)
logFormatter.TimestampFormat = time.RFC3339 // or RFC3339
logFormatter.FullTimestamp = true
logFormatter.CallerPrettyfier = func(frame *runtime.Frame) (function string, file string) {
fileName := path.Base(frame.File) + ":" + strconv.Itoa(frame.Line)
//return frame.Function, fileName
return "", fileName
}
if level == log.DebugLevel {
log.SetReportCaller(true)
}
log.SetFormatter(logFormatter)
log.SetLevel(level)