Skip to content

Commit

Permalink
fix: Fix to make mender-connect request a new JWT token on its own, s…
Browse files Browse the repository at this point in the history
…o its not dependent on mender-update to do so

Changelog: Title

Ticket: MEN-6877
Signed-off-by: Sebastian Opsahl <sebastian.opsahl@northern.tech>
  • Loading branch information
SebOpsahl committed Feb 29, 2024
1 parent 046bf46 commit c0e2284
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 87 deletions.
51 changes: 22 additions & 29 deletions app/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,47 +322,40 @@ func (d *MenderShellDaemon) dbusEventLoop(client mender.AuthClient) {
if len(p) > 1 &&
p[0].ParamType == dbus.GDBusTypeString &&
p[1].ParamType == dbus.GDBusTypeString {

token := p[0].ParamData.(string)
serverURL := p[1].ParamData.(string)
d.processJwtTokenStateChange(token, serverURL)

if len(token) > 0 && len(serverURL) > 0 {
log.Tracef("dbusEventLoop: got a token len=%d, ServerURL=%s", len(token), serverURL)
if token != d.serverJwt || serverURL != d.serverUrl {
log.Debugf(
"dbusEventLoop: new token or ServerURL, reconnecting. len=%d, ServerURL=%s",
len(token),
serverURL,
)
needsReconnect = true

// If the server (Mender client proxy) closed the connection, it is likely that
// both messageLoop is asking for a reconnection and we got JwtTokenStateChange
// signal. So drain here the reconnect channel and reconnect only once
if d.needsReconnect() {
log.Debug("dbusEventLoop: drained reconnect req channel")
}

e := MenderShellDaemonEvent{
event: EventReconnect,
data: token,
id: "(dbusEventLoop)",
}
// TODO: moving these assignments one scope up would make d.authorized redundant...
d.serverJwt = token
log.Tracef("(dbusEventLoop) posting Event: %s", e.event)
d.serverUrl = serverURL
d.serverJwt = token
d.postEvent(e)
needsReconnect = false

// If the server (Mender client proxy) closed the connection, it is likely that
// both messageLoop is asking for a reconnection and we got JwtTokenStateChange
// signal. So drain here the reconnect channel and reconnect only once
if d.needsReconnect() {
log.Debug("dbusEventLoop: drained reconnect req channel")
}
}
}
if needsReconnect && d.authorized {
jwtToken, serverURL, _ := client.GetJWTToken()
e := MenderShellDaemonEvent{
event: EventReconnect,
data: jwtToken,
id: "(dbusEventLoop)",

if needsReconnect {
_, err := client.FetchJWTToken()
if err != nil {
log.Errorf("dbusEventLoop: error fetching JWT token")
}
log.Tracef("(dbusEventLoop) posting Event: %s", e.event)
d.serverUrl = serverURL
d.serverJwt = jwtToken
d.postEvent(e)
needsReconnect = false
}
}

log.Trace("dbusEventLoop: returning")
}

Expand Down
140 changes: 83 additions & 57 deletions app/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,94 +739,120 @@ func TestTimeToSweepSessions(t *testing.T) {
func TestDBusEventLoop(t *testing.T) {
currentUser, err := user.Current()
if err != nil {
t.Errorf("cant get current user: %s", err.Error())
return
t.Fatalf("cant get current user: %s", err)
}

testCases := []struct {
name string
err error
token string
err error
timeout time.Duration
}{
{
name: "stopped-gracefully",
token: "the-token",
name: "stopped-gracefully",
token: "the-token",
timeout: 4 * time.Second,
},
{
name: "token_not_returned_wait_forever",
token: "",
timeout: 15 * time.Second,
},
{
name: "token_not_returned_try_reconnection",
token: "",
timeout: 2 * time.Second,
},
}

for _, tc := range testCases {
if tc.name == "token_not_returned_wait_forever" {
timeout := time.After(tc.timeout)
done := make(chan bool)
go func() {
t.Run(tc.name, func(t *testing.T) {
d := NewDaemon(&config.MenderShellConfig{
MenderShellConfigFromFile: config.MenderShellConfigFromFile{
ShellCommand: "/bin/sh",
User: currentUser.Name,
Terminal: config.TerminalConfig{
Width: 24,
Height: 80,
t.Run(tc.name, func(t *testing.T) {
d := NewDaemon(&config.MenderShellConfig{
MenderShellConfigFromFile: config.MenderShellConfigFromFile{
ShellCommand: "/bin/sh",
User: currentUser.Name,
Terminal: config.TerminalConfig{
Width: 24,
Height: 80,
},
},
})

dbusAPI := &dbusmocks.DBusAPI{}
defer dbusAPI.AssertExpectations(t)
client := &authmocks.AuthClient{}

switch tc.name {
case "token_not_returned_wait_forever":
timeout := time.After(tc.timeout)
done := make(chan bool)
go func() {
t.Run(tc.name, func(t *testing.T) {
client.On("WaitForJwtTokenStateChange").Return([]dbus.SignalParams{
{
ParamType: "",
ParamData: nil,
},
},
}, tc.err)
d.dbusEventLoop(client)
})
done <- true
}()
select {
case <-timeout:
t.Logf("ok: expected to run forever")
case <-done:
}

dbusAPI := &dbusmocks.DBusAPI{}
defer dbusAPI.AssertExpectations(t)
client := &authmocks.AuthClient{}
case "stopped-gracefully":
timeout := time.After(tc.timeout)
done := make(chan bool)
t.Run(tc.name, func(t *testing.T) {
client.On("WaitForJwtTokenStateChange").Return([]dbus.SignalParams{
{
ParamType: "s",
ParamData: tc.token,
},
}, tc.err)
client.On("GetJWTToken").Return(tc.token, "", tc.err)
d.dbusEventLoop(client)
})
done <- true
}()

select {
case <-timeout:
t.Logf("ok: expected to run forever")
case <-done:
}
} else {
t.Run(tc.name, func(t *testing.T) {
d := NewDaemon(&config.MenderShellConfig{
MenderShellConfigFromFile: config.MenderShellConfigFromFile{
ShellCommand: "/bin/sh",
User: currentUser.Name,
Terminal: config.TerminalConfig{
Width: 24,
Height: 80,
},
},
go func() {
d.dbusEventLoop(client)
done <- true
}()

select {
case <-timeout:
client.AssertNotCalled(t, "FetchJWTToken")
d.stop = true
<-done
case <-done:
t.Error("dbusEventLoop returned unexpectedly early")
}
})

dbusAPI := &dbusmocks.DBusAPI{}
defer dbusAPI.AssertExpectations(t)
client := &authmocks.AuthClient{}
client.On("WaitForJwtTokenStateChange").Return([]dbus.SignalParams{
{
ParamType: "s",
ParamData: tc.token,
},
}, tc.err)
client.On("GetJWTToken").Return(tc.token, "", tc.err)
case "token_not_returned_try_reconnection":
timeout := time.After(tc.timeout)
done := make(chan bool)
go func() {
time.Sleep(time.Second)
d.stop = true
t.Run(tc.name, func(t *testing.T) {
client.On("WaitForJwtTokenStateChange").Return([]dbus.SignalParams{
{
ParamType: "",
ParamData: nil,
},
}, tc.err)
d.dbusEventLoop(client)
client.AssertCalled(t, "FetchJWTToken")
})
done <- true
}()
d.dbusEventLoop(client)
})
}
select {
case <-timeout:
t.Logf("ok: expected to run forever")
case <-done:
}
}
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion client/mender/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const (

var timeout = 10 * time.Second

// AuthClient is the interface for the Mender Authentication Manager clilents
// AuthClient is the interface for the Mender Authentication Manager clients
type AuthClient interface {
// Connect to the Mender client interface
Connect(objectName, objectPath, interfaceName string) error
Expand Down

0 comments on commit c0e2284

Please sign in to comment.