Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ var ErrInvalidCredentials = fmt.Errorf("invalid credentials")
var ErrInvalidCode = fmt.Errorf("invalid enrollment code")

type ConfigMeta struct {
Org ConfigOrg
Network ConfigNetwork
Host ConfigHost
Org ConfigOrg
Network ConfigNetwork
Host ConfigHost
EndpointOIDC *ConfigEndpointOIDC
}

type ConfigOrg struct {
Expand All @@ -104,6 +105,10 @@ type ConfigHost struct {
IPAddress string
}

type ConfigEndpointOIDC struct {
Email string
}

// Enroll issues an enrollment request against the REST API using the given enrollment code, passing along a locally
// generated DH X25519 public key to be signed by the CA, and an Ed 25519 public key for future API call authentication.
// On success it returns the Nebula config generated by the server, a Nebula private key PEM to be inserted into the
Expand Down Expand Up @@ -204,6 +209,12 @@ func (c *Client) Enroll(ctx context.Context, logger logrus.FieldLogger, code str
},
}

if r.Data.EndpointOIDCMeta != nil {
meta.EndpointOIDC = &ConfigEndpointOIDC{
Email: r.Data.EndpointOIDCMeta.Email,
}
}

// Determine the private keys to save based on the network curve type
var privkeyPEM []byte
var privkey keys.PrivateKey
Expand Down Expand Up @@ -382,6 +393,12 @@ func (c *Client) DoUpdate(ctx context.Context, creds keys.Credentials) ([]byte,
},
}

if result.EndpointOIDCMeta != nil {
meta.EndpointOIDC = &ConfigEndpointOIDC{
Email: result.EndpointOIDCMeta.Email,
}
}

return result.Config, nebulaPrivkeyPEM, newCreds, meta, nil
}

Expand Down
15 changes: 14 additions & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func TestEnroll(t *testing.T) {
hostID := "foobar"
hostName := "foo host"
hostIP := "192.168.100.1"
oidcEmail := "[email protected]"
counter := uint(5)
ca, _ := dnapitest.NebulaCACert()
caPEM, err := ca.MarshalToPEM()
Expand Down Expand Up @@ -92,6 +93,9 @@ func TestEnroll(t *testing.T) {
Name: hostName,
IPAddress: hostIP,
},
EndpointOIDCMeta: &message.HostEndpointOIDCMetadata{
Email: oidcEmail,
},
},
})
})
Expand Down Expand Up @@ -139,6 +143,7 @@ func TestEnroll(t *testing.T) {
assert.Equal(t, hostID, meta.Host.ID)
assert.Equal(t, hostName, meta.Host.Name)
assert.Equal(t, hostIP, meta.Host.IPAddress)
assert.Equal(t, oidcEmail, meta.EndpointOIDC.Email)

// Test error handling
errorMsg := "invalid enrollment code"
Expand Down Expand Up @@ -377,6 +382,7 @@ func TestDoUpdate(t *testing.T) {
hostID := "foobar"
hostName := "foo host"
hostIP := "192.168.100.1"
oidcEmail := "[email protected]"

// This time sign the response with the correct CA key.
ts.ExpectDNClientRequest(message.DoUpdate, http.StatusOK, func(r message.RequestWrapper) []byte {
Expand All @@ -400,6 +406,9 @@ func TestDoUpdate(t *testing.T) {
Name: hostName,
IPAddress: hostIP,
},
EndpointOIDCMeta: &message.HostEndpointOIDCMetadata{
Email: oidcEmail,
},
}
rawRes := jsonMarshal(newConfigResponse)

Expand Down Expand Up @@ -427,6 +436,7 @@ func TestDoUpdate(t *testing.T) {
assert.Equal(t, hostID, meta.Host.ID)
assert.Equal(t, hostName, meta.Host.Name)
assert.Equal(t, hostIP, meta.Host.IPAddress)
assert.Equal(t, oidcEmail, meta.EndpointOIDC.Email)
Copy link
Member

@johnmaguire johnmaguire Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for completeness sake, you could add a assert.Nil(t, meta.EndpointOIDC) to an existing test. dubious value maybe


}

Expand Down Expand Up @@ -727,7 +737,7 @@ func TestCommandResponse(t *testing.T) {

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
config, pkey, creds, _, err := c.Enroll(ctx, testutil.NewTestLogger(), "foobar")
config, pkey, creds, meta, err := c.Enroll(ctx, testutil.NewTestLogger(), "foobar")
require.NoError(t, err)

// make sure all credential values were set
Expand All @@ -740,6 +750,9 @@ func TestCommandResponse(t *testing.T) {
assert.NotEmpty(t, config)
assert.NotEmpty(t, pkey)

// no EndpointOIDC for standard host enrollments
assert.Nil(t, meta.EndpointOIDC)

// This time sign the response with the correct CA key.
responseToken := "abc123"
res := map[string]any{"msg": "Hello, world!"}
Expand Down
35 changes: 21 additions & 14 deletions message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ type DoUpdateRequest struct {

// DoUpdateResponse is the response generated for a DoUpdate request.
type DoUpdateResponse struct {
Config []byte `json:"config"`
Counter uint `json:"counter"`
Nonce []byte `json:"nonce"`
TrustedKeys []byte `json:"trustedKeys"`
Organization HostOrgMetadata `json:"organization"`
Network HostNetworkMetadata `json:"network"`
Host HostHostMetadata `json:"host"`
Config []byte `json:"config"`
Counter uint `json:"counter"`
Nonce []byte `json:"nonce"`
TrustedKeys []byte `json:"trustedKeys"`
Organization HostOrgMetadata `json:"organization"`
Network HostNetworkMetadata `json:"network"`
Host HostHostMetadata `json:"host"`
EndpointOIDCMeta *HostEndpointOIDCMetadata `json:"endpointOIDC"`
}

// LongPollWaitResponseWrapper contains a response to LongPollWait inside "data."
Expand Down Expand Up @@ -152,13 +153,14 @@ type EnrollResponse struct {

// EnrollResponseData is included in the EnrollResponse.
type EnrollResponseData struct {
Config []byte `json:"config"`
HostID string `json:"hostID"`
Counter uint `json:"counter"`
TrustedKeys []byte `json:"trustedKeys"`
Organization HostOrgMetadata `json:"organization"`
Network HostNetworkMetadata `json:"network"`
Host HostHostMetadata `json:"host"`
Config []byte `json:"config"`
HostID string `json:"hostID"`
Counter uint `json:"counter"`
TrustedKeys []byte `json:"trustedKeys"`
Organization HostOrgMetadata `json:"organization"`
Network HostNetworkMetadata `json:"network"`
Host HostHostMetadata `json:"host"`
EndpointOIDCMeta *HostEndpointOIDCMetadata `json:"endpointOIDC"`
}

// HostOrgMetadata is included in EnrollResponseData.
Expand All @@ -182,6 +184,11 @@ type HostHostMetadata struct {
IPAddress string `json:"ipAddress"`
}

// HostEndpointOIDCMetadata is included in EnrollResponseData.
type HostEndpointOIDCMetadata struct {
Email string `json:"email"`
}

// APIError represents a single error returned in an API error response.
type APIError struct {
Code string `json:"code"`
Expand Down
Loading