Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59541b5c20 | ||
|
|
75125883df | ||
|
|
d8ca49b6de | ||
|
|
50fc47200a | ||
|
|
b75274f7e7 | ||
|
|
fa9c1c3b24 | ||
|
|
86f3e9ec78 | ||
|
|
9aaa05e8ea | ||
|
|
0af5a0441f | ||
|
|
0fc63ea0ba | ||
|
|
c935639a96 | ||
|
|
afe383fa2d |
No files matched your search
@@ -33,6 +33,7 @@ require (
|
||||
github.com/awnumar/memguard v0.23.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2
|
||||
github.com/c-robinson/iplib v1.0.3
|
||||
github.com/caddyserver/certmagic v0.21.3
|
||||
@@ -143,7 +144,6 @@ require (
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/awnumar/memcall v0.4.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
|
||||
@@ -850,7 +850,7 @@ func IsPortBasedProtocol(mode string) bool {
|
||||
}
|
||||
|
||||
const (
|
||||
maxCustomHeaders = 16
|
||||
maxCustomHeaders = 16
|
||||
maxHeaderKeyLen = 128
|
||||
maxHeaderValueLen = 4096
|
||||
)
|
||||
@@ -947,7 +947,6 @@ func containsCRLF(s string) bool {
|
||||
}
|
||||
|
||||
func validateHeaderAuths(headers []*HeaderAuthConfig) error {
|
||||
seen := make(map[string]struct{})
|
||||
for i, h := range headers {
|
||||
if h == nil || !h.Enabled {
|
||||
continue
|
||||
@@ -968,10 +967,6 @@ func validateHeaderAuths(headers []*HeaderAuthConfig) error {
|
||||
if canonical == "Host" {
|
||||
return fmt.Errorf("header_auths[%d]: Host header cannot be used for auth", i)
|
||||
}
|
||||
if _, dup := seen[canonical]; dup {
|
||||
return fmt.Errorf("header_auths[%d]: duplicate header %q (same canonical form already configured)", i, h.Header)
|
||||
}
|
||||
seen[canonical] = struct{}{}
|
||||
if len(h.Value) > maxHeaderValueLen {
|
||||
return fmt.Errorf("header_auths[%d]: value exceeds maximum length of %d", i, maxHeaderValueLen)
|
||||
}
|
||||
|
||||
@@ -935,3 +935,107 @@ func TestExposeServiceRequest_Validate_HTTPAllowsAuth(t *testing.T) {
|
||||
req := ExposeServiceRequest{Port: 8080, Mode: "http", Pin: "123456"}
|
||||
require.NoError(t, req.Validate())
|
||||
}
|
||||
|
||||
func TestValidate_HeaderAuths(t *testing.T) {
|
||||
t.Run("single valid header", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "X-API-Key", Value: "secret"},
|
||||
},
|
||||
}
|
||||
require.NoError(t, rp.Validate())
|
||||
})
|
||||
|
||||
t.Run("multiple headers same canonical name allowed", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "Authorization", Value: "Bearer token-1"},
|
||||
{Enabled: true, Header: "Authorization", Value: "Bearer token-2"},
|
||||
},
|
||||
}
|
||||
require.NoError(t, rp.Validate())
|
||||
})
|
||||
|
||||
t.Run("multiple headers different case same canonical allowed", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "x-api-key", Value: "key-1"},
|
||||
{Enabled: true, Header: "X-Api-Key", Value: "key-2"},
|
||||
},
|
||||
}
|
||||
require.NoError(t, rp.Validate())
|
||||
})
|
||||
|
||||
t.Run("multiple different headers allowed", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "Authorization", Value: "Bearer tok"},
|
||||
{Enabled: true, Header: "X-API-Key", Value: "key"},
|
||||
},
|
||||
}
|
||||
require.NoError(t, rp.Validate())
|
||||
})
|
||||
|
||||
t.Run("empty header name rejected", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "", Value: "val"},
|
||||
},
|
||||
}
|
||||
err := rp.Validate()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "header name is required")
|
||||
})
|
||||
|
||||
t.Run("hop-by-hop header rejected", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "Connection", Value: "val"},
|
||||
},
|
||||
}
|
||||
err := rp.Validate()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "hop-by-hop")
|
||||
})
|
||||
|
||||
t.Run("host header rejected", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "Host", Value: "val"},
|
||||
},
|
||||
}
|
||||
err := rp.Validate()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "Host header cannot be used")
|
||||
})
|
||||
|
||||
t.Run("disabled entries skipped", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: false, Header: "", Value: ""},
|
||||
{Enabled: true, Header: "X-Key", Value: "val"},
|
||||
},
|
||||
}
|
||||
require.NoError(t, rp.Validate())
|
||||
})
|
||||
|
||||
t.Run("value too long rejected", func(t *testing.T) {
|
||||
rp := validProxy()
|
||||
rp.Auth = AuthConfig{
|
||||
HeaderAuths: []*HeaderAuthConfig{
|
||||
{Enabled: true, Header: "X-Key", Value: strings.Repeat("a", maxHeaderValueLen+1)},
|
||||
},
|
||||
}
|
||||
err := rp.Validate()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "exceeds maximum length")
|
||||
})
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func (am *DefaultAccountManager) UpdatePeer(ctx context.Context, accountID, user
|
||||
if err != nil {
|
||||
newLabel = ""
|
||||
} else {
|
||||
_, err := transaction.GetPeerIdByLabel(ctx, store.LockingStrengthNone, accountID, update.Name)
|
||||
_, err := transaction.GetPeerIdByLabel(ctx, store.LockingStrengthNone, accountID, newLabel)
|
||||
if err == nil {
|
||||
newLabel = ""
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/netbirdio/netbird/management/server/job"
|
||||
"github.com/netbirdio/netbird/management/server/permissions"
|
||||
"github.com/netbirdio/netbird/management/server/settings"
|
||||
"github.com/netbirdio/netbird/shared/auth"
|
||||
"github.com/netbirdio/netbird/shared/management/status"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/util"
|
||||
@@ -2738,3 +2739,70 @@ func TestProcessPeerAddAuth(t *testing.T) {
|
||||
assert.Empty(t, config.GroupsToAdd)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdatePeer_DnsLabelCollisionWithFQDN(t *testing.T) {
|
||||
manager, _, err := createManager(t)
|
||||
require.NoError(t, err, "unable to create account manager")
|
||||
|
||||
accountID, err := manager.GetAccountIDByUserID(context.Background(), auth.UserAuth{UserId: userID})
|
||||
require.NoError(t, err, "unable to create an account")
|
||||
|
||||
// Add first peer with hostname that produces DNS label "netbird1"
|
||||
key1, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "netbird1.netbird.cloud"},
|
||||
}, false)
|
||||
require.NoError(t, err, "unable to add first peer")
|
||||
assert.Equal(t, "netbird1", peer1.DNSLabel)
|
||||
|
||||
// Add second peer with a different hostname
|
||||
key2, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "ip-10-29-5-130"},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
update := peer2.Copy()
|
||||
update.Name = "netbird1.demo.netbird.cloud"
|
||||
updated, err := manager.UpdatePeer(context.Background(), accountID, userID, update)
|
||||
require.NoError(t, err, "renaming peer should not fail with duplicate DNS label error")
|
||||
assert.Equal(t, "netbird1.demo.netbird.cloud", updated.Name)
|
||||
assert.NotEqual(t, "netbird1", updated.DNSLabel, "DNS label should not collide with existing peer")
|
||||
assert.Contains(t, updated.DNSLabel, "netbird1-", "DNS label should be IP-based fallback")
|
||||
}
|
||||
|
||||
func TestUpdatePeer_DnsLabelUniqueName(t *testing.T) {
|
||||
manager, _, err := createManager(t)
|
||||
require.NoError(t, err, "unable to create account manager")
|
||||
|
||||
accountID, err := manager.GetAccountIDByUserID(context.Background(), auth.UserAuth{UserId: userID})
|
||||
require.NoError(t, err, "unable to create an account")
|
||||
|
||||
key1, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "web-server"},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "web-server", peer1.DNSLabel)
|
||||
|
||||
// Add second peer and rename it to a unique FQDN whose first label doesn't collide
|
||||
key2, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "old-name"},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
update := peer2.Copy()
|
||||
update.Name = "api-server.example.com"
|
||||
updated, err := manager.UpdatePeer(context.Background(), accountID, userID, update)
|
||||
require.NoError(t, err, "renaming to unique FQDN should succeed")
|
||||
assert.Equal(t, "api-server", updated.DNSLabel, "DNS label should be first label of FQDN")
|
||||
}
|
||||
@@ -932,3 +932,71 @@ func TestProtect_HeaderAuth_SubsequentRequestUsesSessionCookie(t *testing.T) {
|
||||
assert.Equal(t, "header-user", capturedData2.GetUserID())
|
||||
assert.Equal(t, "header", capturedData2.GetAuthMethod())
|
||||
}
|
||||
|
||||
// TestProtect_HeaderAuth_MultipleValuesSameHeader verifies that the proxy
|
||||
// correctly handles multiple valid credentials for the same header name.
|
||||
// In production, the mgmt gRPC authenticateHeader iterates all configured
|
||||
// header auths and accepts if any hash matches (OR semantics). The proxy
|
||||
// creates one Header scheme per entry, but a single gRPC call checks all.
|
||||
func TestProtect_HeaderAuth_MultipleValuesSameHeader(t *testing.T) {
|
||||
mw := NewMiddleware(log.StandardLogger(), nil, nil)
|
||||
kp := generateTestKeyPair(t)
|
||||
|
||||
// Mock simulates mgmt behavior: accepts either token-a or token-b.
|
||||
accepted := map[string]bool{"Bearer token-a": true, "Bearer token-b": true}
|
||||
mock := &mockAuthenticator{fn: func(_ context.Context, req *proto.AuthenticateRequest) (*proto.AuthenticateResponse, error) {
|
||||
ha := req.GetHeaderAuth()
|
||||
if ha != nil && accepted[ha.GetHeaderValue()] {
|
||||
token, err := sessionkey.SignToken(kp.PrivateKey, "header-user", "example.com", auth.MethodHeader, time.Hour)
|
||||
require.NoError(t, err)
|
||||
return &proto.AuthenticateResponse{Success: true, SessionToken: token}, nil
|
||||
}
|
||||
return &proto.AuthenticateResponse{Success: false}, nil
|
||||
}}
|
||||
|
||||
// Single Header scheme (as if one entry existed), but the mock checks both values.
|
||||
hdr := NewHeader(mock, "svc1", "acc1", "Authorization")
|
||||
require.NoError(t, mw.AddDomain("example.com", []Scheme{hdr}, kp.PublicKey, time.Hour, "acc1", "svc1", nil))
|
||||
|
||||
var backendCalled bool
|
||||
handler := mw.Protect(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
backendCalled = true
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
t.Run("first value accepted", func(t *testing.T) {
|
||||
backendCalled = false
|
||||
req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-a")
|
||||
req = req.WithContext(proxy.WithCapturedData(req.Context(), proxy.NewCapturedData("")))
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
assert.True(t, backendCalled, "first token should be accepted")
|
||||
})
|
||||
|
||||
t.Run("second value accepted", func(t *testing.T) {
|
||||
backendCalled = false
|
||||
req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-b")
|
||||
req = req.WithContext(proxy.WithCapturedData(req.Context(), proxy.NewCapturedData("")))
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
assert.True(t, backendCalled, "second token should be accepted")
|
||||
})
|
||||
|
||||
t.Run("unknown value rejected", func(t *testing.T) {
|
||||
backendCalled = false
|
||||
req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-c")
|
||||
req = req.WithContext(proxy.WithCapturedData(req.Context(), proxy.NewCapturedData("")))
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, rec.Code)
|
||||
assert.False(t, backendCalled, "unknown token should be rejected")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// AzureIDPAPI APIs for Azure AD IDP integrations
|
||||
type AzureIDPAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List retrieves all Azure AD IDP integrations
|
||||
func (a *AzureIDPAPI) List(ctx context.Context) ([]api.AzureIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/azure-idp", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.AzureIntegration](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves a specific Azure AD IDP integration by ID
|
||||
func (a *AzureIDPAPI) Get(ctx context.Context, integrationID string) (*api.AzureIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/azure-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.AzureIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create creates a new Azure AD IDP integration
|
||||
func (a *AzureIDPAPI) Create(ctx context.Context, request api.CreateAzureIntegrationRequest) (*api.AzureIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/azure-idp", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.AzureIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update updates an existing Azure AD IDP integration
|
||||
func (a *AzureIDPAPI) Update(ctx context.Context, integrationID string, request api.UpdateAzureIntegrationRequest) (*api.AzureIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/azure-idp/"+integrationID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.AzureIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete deletes an Azure AD IDP integration
|
||||
func (a *AzureIDPAPI) Delete(ctx context.Context, integrationID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/azure-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sync triggers a manual sync for an Azure AD IDP integration
|
||||
func (a *AzureIDPAPI) Sync(ctx context.Context, integrationID string) (*api.SyncResult, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/azure-idp/"+integrationID+"/sync", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.SyncResult](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetLogs retrieves synchronization logs for an Azure AD IDP integration
|
||||
func (a *AzureIDPAPI) GetLogs(ctx context.Context, integrationID string) ([]api.IdpIntegrationSyncLog, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/azure-idp/"+integrationID+"/logs", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IdpIntegrationSyncLog](resp)
|
||||
return ret, err
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var testAzureIntegration = api.AzureIntegration{
|
||||
Id: 1,
|
||||
Enabled: true,
|
||||
ClientId: "12345678-1234-1234-1234-123456789012",
|
||||
TenantId: "87654321-4321-4321-4321-210987654321",
|
||||
SyncInterval: 300,
|
||||
GroupPrefixes: []string{"eng-"},
|
||||
UserGroupPrefixes: []string{"dev-"},
|
||||
Host: "microsoft.com",
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
func TestAzureIDP_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.AzureIntegration{testAzureIntegration})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testAzureIntegration, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testAzureIntegration)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Get(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testAzureIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Get(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateAzureIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "12345678-1234-1234-1234-123456789012", req.ClientId)
|
||||
retBytes, _ := json.Marshal(testAzureIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Create(context.Background(), api.CreateAzureIntegrationRequest{
|
||||
ClientId: "12345678-1234-1234-1234-123456789012",
|
||||
ClientSecret: "secret",
|
||||
TenantId: "87654321-4321-4321-4321-210987654321",
|
||||
Host: api.CreateAzureIntegrationRequestHostMicrosoftCom,
|
||||
GroupPrefixes: &[]string{"eng-"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testAzureIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Create(context.Background(), api.CreateAzureIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.UpdateAzureIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, *req.Enabled)
|
||||
retBytes, _ := json.Marshal(testAzureIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Update(context.Background(), "int-1", api.UpdateAzureIntegrationRequest{
|
||||
Enabled: ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testAzureIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Update(context.Background(), "int-1", api.UpdateAzureIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.AzureIDP.Delete(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.AzureIDP.Delete(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Sync_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1/sync", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(api.SyncResult{Result: ptr("ok")})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Sync(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "ok", *ret.Result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_Sync_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1/sync", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.Sync(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_GetLogs_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.IdpIntegrationSyncLog{testSyncLog})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.GetLogs(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testSyncLog, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestAzureIDP_GetLogs_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/azure-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.AzureIDP.GetLogs(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
@@ -110,6 +110,15 @@ type Client struct {
|
||||
// see more: https://docs.netbird.io/api/resources/scim
|
||||
SCIM *SCIMAPI
|
||||
|
||||
// GoogleIDP NetBird Google Workspace IDP integration APIs
|
||||
GoogleIDP *GoogleIDPAPI
|
||||
|
||||
// AzureIDP NetBird Azure AD IDP integration APIs
|
||||
AzureIDP *AzureIDPAPI
|
||||
|
||||
// OktaScimIDP NetBird Okta SCIM IDP integration APIs
|
||||
OktaScimIDP *OktaScimIDPAPI
|
||||
|
||||
// EventStreaming NetBird Event Streaming integration APIs
|
||||
// see more: https://docs.netbird.io/api/resources/event-streaming
|
||||
EventStreaming *EventStreamingAPI
|
||||
@@ -185,6 +194,9 @@ func (c *Client) initialize() {
|
||||
c.MSP = &MSPAPI{c}
|
||||
c.EDR = &EDRAPI{c}
|
||||
c.SCIM = &SCIMAPI{c}
|
||||
c.GoogleIDP = &GoogleIDPAPI{c}
|
||||
c.AzureIDP = &AzureIDPAPI{c}
|
||||
c.OktaScimIDP = &OktaScimIDPAPI{c}
|
||||
c.EventStreaming = &EventStreamingAPI{c}
|
||||
c.IdentityProviders = &IdentityProvidersAPI{c}
|
||||
c.Ingress = &IngressAPI{c}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// GoogleIDPAPI APIs for Google Workspace IDP integrations
|
||||
type GoogleIDPAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List retrieves all Google Workspace IDP integrations
|
||||
func (a *GoogleIDPAPI) List(ctx context.Context) ([]api.GoogleIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/google-idp", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.GoogleIntegration](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves a specific Google Workspace IDP integration by ID
|
||||
func (a *GoogleIDPAPI) Get(ctx context.Context, integrationID string) (*api.GoogleIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/google-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.GoogleIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create creates a new Google Workspace IDP integration
|
||||
func (a *GoogleIDPAPI) Create(ctx context.Context, request api.CreateGoogleIntegrationRequest) (*api.GoogleIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/google-idp", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.GoogleIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update updates an existing Google Workspace IDP integration
|
||||
func (a *GoogleIDPAPI) Update(ctx context.Context, integrationID string, request api.UpdateGoogleIntegrationRequest) (*api.GoogleIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/google-idp/"+integrationID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.GoogleIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete deletes a Google Workspace IDP integration
|
||||
func (a *GoogleIDPAPI) Delete(ctx context.Context, integrationID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/google-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sync triggers a manual sync for a Google Workspace IDP integration
|
||||
func (a *GoogleIDPAPI) Sync(ctx context.Context, integrationID string) (*api.SyncResult, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/google-idp/"+integrationID+"/sync", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.SyncResult](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetLogs retrieves synchronization logs for a Google Workspace IDP integration
|
||||
func (a *GoogleIDPAPI) GetLogs(ctx context.Context, integrationID string) ([]api.IdpIntegrationSyncLog, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/google-idp/"+integrationID+"/logs", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IdpIntegrationSyncLog](resp)
|
||||
return ret, err
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var testGoogleIntegration = api.GoogleIntegration{
|
||||
Id: 1,
|
||||
Enabled: true,
|
||||
CustomerId: "C01234567",
|
||||
SyncInterval: 300,
|
||||
GroupPrefixes: []string{"eng-"},
|
||||
UserGroupPrefixes: []string{"dev-"},
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
func TestGoogleIDP_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.GoogleIntegration{testGoogleIntegration})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testGoogleIntegration, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testGoogleIntegration)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Get(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGoogleIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Get(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateGoogleIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "C01234567", req.CustomerId)
|
||||
retBytes, _ := json.Marshal(testGoogleIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Create(context.Background(), api.CreateGoogleIntegrationRequest{
|
||||
CustomerId: "C01234567",
|
||||
ServiceAccountKey: "key-data",
|
||||
GroupPrefixes: &[]string{"eng-"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGoogleIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Create(context.Background(), api.CreateGoogleIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.UpdateGoogleIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, *req.Enabled)
|
||||
retBytes, _ := json.Marshal(testGoogleIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Update(context.Background(), "int-1", api.UpdateGoogleIntegrationRequest{
|
||||
Enabled: ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGoogleIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Update(context.Background(), "int-1", api.UpdateGoogleIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.GoogleIDP.Delete(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.GoogleIDP.Delete(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Sync_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1/sync", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(api.SyncResult{Result: ptr("ok")})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Sync(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "ok", *ret.Result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_Sync_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1/sync", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.Sync(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_GetLogs_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.IdpIntegrationSyncLog{testSyncLog})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.GetLogs(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testSyncLog, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoogleIDP_GetLogs_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/google-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GoogleIDP.GetLogs(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
|
||||
// OktaScimIDPAPI APIs for Okta SCIM IDP integrations
|
||||
type OktaScimIDPAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List retrieves all Okta SCIM IDP integrations
|
||||
func (a *OktaScimIDPAPI) List(ctx context.Context) ([]api.OktaScimIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/okta-scim-idp", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.OktaScimIntegration](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves a specific Okta SCIM IDP integration by ID
|
||||
func (a *OktaScimIDPAPI) Get(ctx context.Context, integrationID string) (*api.OktaScimIntegration, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/okta-scim-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.OktaScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create creates a new Okta SCIM IDP integration
|
||||
func (a *OktaScimIDPAPI) Create(ctx context.Context, request api.CreateOktaScimIntegrationRequest) (*api.OktaScimIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/okta-scim-idp", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.OktaScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update updates an existing Okta SCIM IDP integration
|
||||
func (a *OktaScimIDPAPI) Update(ctx context.Context, integrationID string, request api.UpdateOktaScimIntegrationRequest) (*api.OktaScimIntegration, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/integrations/okta-scim-idp/"+integrationID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.OktaScimIntegration](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete deletes an Okta SCIM IDP integration
|
||||
func (a *OktaScimIDPAPI) Delete(ctx context.Context, integrationID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/integrations/okta-scim-idp/"+integrationID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegenerateToken regenerates the SCIM API token for an Okta SCIM integration
|
||||
func (a *OktaScimIDPAPI) RegenerateToken(ctx context.Context, integrationID string) (*api.ScimTokenResponse, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/integrations/okta-scim-idp/"+integrationID+"/token", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[api.ScimTokenResponse](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// GetLogs retrieves synchronization logs for an Okta SCIM IDP integration
|
||||
func (a *OktaScimIDPAPI) GetLogs(ctx context.Context, integrationID string) ([]api.IdpIntegrationSyncLog, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/integrations/okta-scim-idp/"+integrationID+"/logs", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
ret, err := parseResponse[[]api.IdpIntegrationSyncLog](resp)
|
||||
return ret, err
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
//go:build integration
|
||||
|
||||
package rest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||
)
|
||||
|
||||
var testOktaScimIntegration = api.OktaScimIntegration{
|
||||
Id: 1,
|
||||
AuthToken: "****",
|
||||
Enabled: true,
|
||||
GroupPrefixes: []string{"eng-"},
|
||||
UserGroupPrefixes: []string{"dev-"},
|
||||
LastSyncedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_List_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.OktaScimIntegration{testOktaScimIntegration})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testOktaScimIntegration, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal(testOktaScimIntegration)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Get(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testOktaScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Get(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.CreateOktaScimIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "my-okta-connection", req.ConnectionName)
|
||||
retBytes, _ := json.Marshal(testOktaScimIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Create(context.Background(), api.CreateOktaScimIntegrationRequest{
|
||||
ConnectionName: "my-okta-connection",
|
||||
GroupPrefixes: &[]string{"eng-"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testOktaScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Create(context.Background(), api.CreateOktaScimIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.UpdateOktaScimIntegrationRequest
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, *req.Enabled)
|
||||
retBytes, _ := json.Marshal(testOktaScimIntegration)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Update(context.Background(), "int-1", api.UpdateOktaScimIntegrationRequest{
|
||||
Enabled: ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testOktaScimIntegration, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.Update(context.Background(), "int-1", api.UpdateOktaScimIntegrationRequest{})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.OktaScimIDP.Delete(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.OktaScimIDP.Delete(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_RegenerateToken_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
retBytes, _ := json.Marshal(testScimToken)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.RegenerateToken(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testScimToken, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_RegenerateToken_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.RegenerateToken(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_GetLogs_200(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "GET", r.Method)
|
||||
retBytes, _ := json.Marshal([]api.IdpIntegrationSyncLog{testSyncLog})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.GetLogs(context.Background(), "int-1")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testSyncLog, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestOktaScimIDP_GetLogs_Err(t *testing.T) {
|
||||
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/integrations/okta-scim-idp/int-1/logs", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.OktaScimIDP.GetLogs(context.Background(), "int-1")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
+1197
-102
File diff suppressed because it is too large.
Load diff
@@ -16,6 +16,24 @@ const (
|
||||
TokenAuthScopes = "TokenAuth.Scopes"
|
||||
)
|
||||
|
||||
// Defines values for CreateAzureIntegrationRequestHost.
|
||||
const (
|
||||
CreateAzureIntegrationRequestHostMicrosoftCom CreateAzureIntegrationRequestHost = "microsoft.com"
|
||||
CreateAzureIntegrationRequestHostMicrosoftUs CreateAzureIntegrationRequestHost = "microsoft.us"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the CreateAzureIntegrationRequestHost enum.
|
||||
func (e CreateAzureIntegrationRequestHost) Valid() bool {
|
||||
switch e {
|
||||
case CreateAzureIntegrationRequestHostMicrosoftCom:
|
||||
return true
|
||||
case CreateAzureIntegrationRequestHostMicrosoftUs:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for CreateIntegrationRequestPlatform.
|
||||
const (
|
||||
CreateIntegrationRequestPlatformDatadog CreateIntegrationRequestPlatform = "datadog"
|
||||
@@ -1450,6 +1468,36 @@ type AvailablePorts struct {
|
||||
Udp int `json:"udp"`
|
||||
}
|
||||
|
||||
// AzureIntegration defines model for AzureIntegration.
|
||||
type AzureIntegration struct {
|
||||
// ClientId Azure AD application (client) ID
|
||||
ClientId string `json:"client_id"`
|
||||
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes []string `json:"group_prefixes"`
|
||||
|
||||
// Host Azure host domain for the Graph API
|
||||
Host string `json:"host"`
|
||||
|
||||
// Id The unique identifier for the integration
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of the last synchronization
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// SyncInterval Sync interval in seconds
|
||||
SyncInterval int `json:"sync_interval"`
|
||||
|
||||
// TenantId Azure AD tenant ID
|
||||
TenantId string `json:"tenant_id"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes []string `json:"user_group_prefixes"`
|
||||
}
|
||||
|
||||
// BearerAuthConfig defines model for BearerAuthConfig.
|
||||
type BearerAuthConfig struct {
|
||||
// DistributionGroups List of group IDs that can use bearer auth
|
||||
@@ -1557,6 +1605,51 @@ type Country struct {
|
||||
// CountryCode 2-letter ISO 3166-1 alpha-2 code that represents the country
|
||||
type CountryCode = string
|
||||
|
||||
// CreateAzureIntegrationRequest defines model for CreateAzureIntegrationRequest.
|
||||
type CreateAzureIntegrationRequest struct {
|
||||
// ClientId Azure AD application (client) ID
|
||||
ClientId string `json:"client_id"`
|
||||
|
||||
// ClientSecret Base64-encoded Azure AD client secret
|
||||
ClientSecret string `json:"client_secret"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// Host Azure host domain for the Graph API
|
||||
Host CreateAzureIntegrationRequestHost `json:"host"`
|
||||
|
||||
// SyncInterval Sync interval in seconds (minimum 300). Defaults to 300 if not specified.
|
||||
SyncInterval *int `json:"sync_interval,omitempty"`
|
||||
|
||||
// TenantId Azure AD tenant ID
|
||||
TenantId string `json:"tenant_id"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// CreateAzureIntegrationRequestHost Azure host domain for the Graph API
|
||||
type CreateAzureIntegrationRequestHost string
|
||||
|
||||
// CreateGoogleIntegrationRequest defines model for CreateGoogleIntegrationRequest.
|
||||
type CreateGoogleIntegrationRequest struct {
|
||||
// CustomerId Customer ID from Google Workspace Account Settings
|
||||
CustomerId string `json:"customer_id"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// ServiceAccountKey Base64-encoded Google service account key
|
||||
ServiceAccountKey string `json:"service_account_key"`
|
||||
|
||||
// SyncInterval Sync interval in seconds (minimum 300). Defaults to 300 if not specified.
|
||||
SyncInterval *int `json:"sync_interval,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// CreateIntegrationRequest Request payload for creating a new event streaming integration. Also used as the structure for the PUT request body, but not all fields are applicable for updates (see PUT operation description).
|
||||
type CreateIntegrationRequest struct {
|
||||
// Config Platform-specific configuration as key-value pairs. For creation, all necessary credentials and settings must be provided. For updates, provide the fields to change or the entire new configuration.
|
||||
@@ -1572,7 +1665,19 @@ type CreateIntegrationRequest struct {
|
||||
// CreateIntegrationRequestPlatform The event streaming platform to integrate with (e.g., "datadog", "s3", "firehose"). This field is used for creation. For updates (PUT), this field, if sent, is ignored by the backend.
|
||||
type CreateIntegrationRequestPlatform string
|
||||
|
||||
// CreateScimIntegrationRequest Request payload for creating an SCIM IDP integration
|
||||
// CreateOktaScimIntegrationRequest defines model for CreateOktaScimIntegrationRequest.
|
||||
type CreateOktaScimIntegrationRequest struct {
|
||||
// ConnectionName The Okta enterprise connection name on Auth0
|
||||
ConnectionName string `json:"connection_name"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// CreateScimIntegrationRequest defines model for CreateScimIntegrationRequest.
|
||||
type CreateScimIntegrationRequest struct {
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
@@ -1947,6 +2052,30 @@ type GeoLocationCheckAction string
|
||||
// GetTenantsResponse defines model for GetTenantsResponse.
|
||||
type GetTenantsResponse = []TenantResponse
|
||||
|
||||
// GoogleIntegration defines model for GoogleIntegration.
|
||||
type GoogleIntegration struct {
|
||||
// CustomerId Customer ID from Google Workspace
|
||||
CustomerId string `json:"customer_id"`
|
||||
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes []string `json:"group_prefixes"`
|
||||
|
||||
// Id The unique identifier for the integration
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of the last synchronization
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// SyncInterval Sync interval in seconds
|
||||
SyncInterval int `json:"sync_interval"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes []string `json:"user_group_prefixes"`
|
||||
}
|
||||
|
||||
// Group defines model for Group.
|
||||
type Group struct {
|
||||
// Id Group ID
|
||||
@@ -2238,6 +2367,12 @@ type InstanceVersionInfo struct {
|
||||
ManagementUpdateAvailable bool `json:"management_update_available"`
|
||||
}
|
||||
|
||||
// IntegrationEnabled defines model for IntegrationEnabled.
|
||||
type IntegrationEnabled struct {
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
// IntegrationResponse Represents an event streaming integration.
|
||||
type IntegrationResponse struct {
|
||||
// AccountId The identifier of the account this integration belongs to.
|
||||
@@ -2265,6 +2400,15 @@ type IntegrationResponse struct {
|
||||
// IntegrationResponsePlatform The event streaming platform.
|
||||
type IntegrationResponsePlatform string
|
||||
|
||||
// IntegrationSyncFilters defines model for IntegrationSyncFilters.
|
||||
type IntegrationSyncFilters struct {
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// InvoicePDFResponse defines model for InvoicePDFResponse.
|
||||
type InvoicePDFResponse struct {
|
||||
// Url URL to redirect the user to invoice.
|
||||
@@ -2684,6 +2828,27 @@ type OSVersionCheck struct {
|
||||
Windows *MinKernelVersionCheck `json:"windows,omitempty"`
|
||||
}
|
||||
|
||||
// OktaScimIntegration defines model for OktaScimIntegration.
|
||||
type OktaScimIntegration struct {
|
||||
// AuthToken SCIM API token (full on creation/regeneration, masked on retrieval)
|
||||
AuthToken string `json:"auth_token"`
|
||||
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes []string `json:"group_prefixes"`
|
||||
|
||||
// Id The unique identifier for the integration
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// LastSyncedAt Timestamp of the last synchronization
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes []string `json:"user_group_prefixes"`
|
||||
}
|
||||
|
||||
// PINAuthConfig defines model for PINAuthConfig.
|
||||
type PINAuthConfig struct {
|
||||
// Enabled Whether PIN auth is enabled
|
||||
@@ -3533,12 +3698,12 @@ type RulePortRange struct {
|
||||
Start int `json:"start"`
|
||||
}
|
||||
|
||||
// ScimIntegration Represents a SCIM IDP integration
|
||||
// ScimIntegration defines model for ScimIntegration.
|
||||
type ScimIntegration struct {
|
||||
// AuthToken SCIM API token (full on creation, masked otherwise)
|
||||
AuthToken string `json:"auth_token"`
|
||||
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
@@ -3550,6 +3715,9 @@ type ScimIntegration struct {
|
||||
// LastSyncedAt Timestamp of when the integration was last synced
|
||||
LastSyncedAt time.Time `json:"last_synced_at"`
|
||||
|
||||
// Prefix The connection prefix used for the SCIM provider
|
||||
Prefix string `json:"prefix"`
|
||||
|
||||
// Provider Name of the SCIM identity provider
|
||||
Provider string `json:"provider"`
|
||||
|
||||
@@ -3951,6 +4119,11 @@ type Subscription struct {
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SyncResult Response for a manual sync trigger
|
||||
type SyncResult struct {
|
||||
Result *string `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
// TenantGroupResponse defines model for TenantGroupResponse.
|
||||
type TenantGroupResponse struct {
|
||||
// Id The Group ID
|
||||
@@ -3996,14 +4169,74 @@ type TenantResponse struct {
|
||||
// TenantResponseStatus The status of the tenant
|
||||
type TenantResponseStatus string
|
||||
|
||||
// UpdateScimIntegrationRequest Request payload for updating an SCIM IDP integration
|
||||
type UpdateScimIntegrationRequest struct {
|
||||
// Enabled Indicates whether the integration is enabled
|
||||
// UpdateAzureIntegrationRequest defines model for UpdateAzureIntegrationRequest.
|
||||
type UpdateAzureIntegrationRequest struct {
|
||||
// ClientId Azure AD application (client) ID
|
||||
ClientId *string `json:"client_id,omitempty"`
|
||||
|
||||
// ClientSecret Base64-encoded Azure AD client secret
|
||||
ClientSecret *string `json:"client_secret,omitempty"`
|
||||
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// SyncInterval Sync interval in seconds (minimum 300)
|
||||
SyncInterval *int `json:"sync_interval,omitempty"`
|
||||
|
||||
// TenantId Azure AD tenant ID
|
||||
TenantId *string `json:"tenant_id,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateGoogleIntegrationRequest defines model for UpdateGoogleIntegrationRequest.
|
||||
type UpdateGoogleIntegrationRequest struct {
|
||||
// CustomerId Customer ID from Google Workspace Account Settings
|
||||
CustomerId *string `json:"customer_id,omitempty"`
|
||||
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// ServiceAccountKey Base64-encoded Google service account key
|
||||
ServiceAccountKey *string `json:"service_account_key,omitempty"`
|
||||
|
||||
// SyncInterval Sync interval in seconds (minimum 300)
|
||||
SyncInterval *int `json:"sync_interval,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateOktaScimIntegrationRequest defines model for UpdateOktaScimIntegrationRequest.
|
||||
type UpdateOktaScimIntegrationRequest struct {
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateScimIntegrationRequest defines model for UpdateScimIntegrationRequest.
|
||||
type UpdateScimIntegrationRequest struct {
|
||||
// Enabled Whether the integration is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
|
||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||
GroupPrefixes *[]string `json:"group_prefixes,omitempty"`
|
||||
|
||||
// Prefix The connection prefix used for the SCIM provider
|
||||
Prefix *string `json:"prefix,omitempty"`
|
||||
|
||||
// UserGroupPrefixes List of start_with string patterns for groups which users to sync
|
||||
UserGroupPrefixes *[]string `json:"user_group_prefixes,omitempty"`
|
||||
}
|
||||
@@ -4513,6 +4746,12 @@ type PostApiIngressPeersJSONRequestBody = IngressPeerCreateRequest
|
||||
// PutApiIngressPeersIngressPeerIdJSONRequestBody defines body for PutApiIngressPeersIngressPeerId for application/json ContentType.
|
||||
type PutApiIngressPeersIngressPeerIdJSONRequestBody = IngressPeerUpdateRequest
|
||||
|
||||
// CreateAzureIntegrationJSONRequestBody defines body for CreateAzureIntegration for application/json ContentType.
|
||||
type CreateAzureIntegrationJSONRequestBody = CreateAzureIntegrationRequest
|
||||
|
||||
// UpdateAzureIntegrationJSONRequestBody defines body for UpdateAzureIntegration for application/json ContentType.
|
||||
type UpdateAzureIntegrationJSONRequestBody = UpdateAzureIntegrationRequest
|
||||
|
||||
// PostApiIntegrationsBillingAwsMarketplaceActivateJSONRequestBody defines body for PostApiIntegrationsBillingAwsMarketplaceActivate for application/json ContentType.
|
||||
type PostApiIntegrationsBillingAwsMarketplaceActivateJSONRequestBody PostApiIntegrationsBillingAwsMarketplaceActivateJSONBody
|
||||
|
||||
@@ -4549,6 +4788,12 @@ type CreateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
||||
// UpdateSentinelOneEDRIntegrationJSONRequestBody defines body for UpdateSentinelOneEDRIntegration for application/json ContentType.
|
||||
type UpdateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
||||
|
||||
// CreateGoogleIntegrationJSONRequestBody defines body for CreateGoogleIntegration for application/json ContentType.
|
||||
type CreateGoogleIntegrationJSONRequestBody = CreateGoogleIntegrationRequest
|
||||
|
||||
// UpdateGoogleIntegrationJSONRequestBody defines body for UpdateGoogleIntegration for application/json ContentType.
|
||||
type UpdateGoogleIntegrationJSONRequestBody = UpdateGoogleIntegrationRequest
|
||||
|
||||
// PostApiIntegrationsMspTenantsJSONRequestBody defines body for PostApiIntegrationsMspTenants for application/json ContentType.
|
||||
type PostApiIntegrationsMspTenantsJSONRequestBody = CreateTenantRequest
|
||||
|
||||
@@ -4564,6 +4809,12 @@ type PostApiIntegrationsMspTenantsIdSubscriptionJSONRequestBody PostApiIntegrati
|
||||
// PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody defines body for PostApiIntegrationsMspTenantsIdUnlink for application/json ContentType.
|
||||
type PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody PostApiIntegrationsMspTenantsIdUnlinkJSONBody
|
||||
|
||||
// CreateOktaScimIntegrationJSONRequestBody defines body for CreateOktaScimIntegration for application/json ContentType.
|
||||
type CreateOktaScimIntegrationJSONRequestBody = CreateOktaScimIntegrationRequest
|
||||
|
||||
// UpdateOktaScimIntegrationJSONRequestBody defines body for UpdateOktaScimIntegration for application/json ContentType.
|
||||
type UpdateOktaScimIntegrationJSONRequestBody = UpdateOktaScimIntegrationRequest
|
||||
|
||||
// CreateSCIMIntegrationJSONRequestBody defines body for CreateSCIMIntegration for application/json ContentType.
|
||||
type CreateSCIMIntegrationJSONRequestBody = CreateScimIntegrationRequest
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
@@ -20,45 +19,55 @@ import (
|
||||
)
|
||||
|
||||
func Test_S3HandlerGetUploadURL(t *testing.T) {
|
||||
if runtime.GOOS != "linux" && os.Getenv("CI") == "true" {
|
||||
t.Skip("Skipping test on non-Linux and CI environment due to docker dependency")
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Skipping test on Windows due to potential docker dependency")
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("Skipping test on non-Linux due to docker dependency")
|
||||
}
|
||||
|
||||
awsEndpoint := "http://127.0.0.1:4566"
|
||||
awsRegion := "us-east-1"
|
||||
|
||||
ctx := context.Background()
|
||||
containerRequest := testcontainers.ContainerRequest{
|
||||
Image: "localstack/localstack:s3-latest",
|
||||
ExposedPorts: []string{"4566:4566/tcp"},
|
||||
WaitingFor: wait.ForLog("Ready"),
|
||||
}
|
||||
|
||||
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: containerRequest,
|
||||
Started: true,
|
||||
ContainerRequest: testcontainers.ContainerRequest{
|
||||
Image: "minio/minio:RELEASE.2025-04-22T22-12-26Z",
|
||||
ExposedPorts: []string{"9000/tcp"},
|
||||
Env: map[string]string{
|
||||
"MINIO_ROOT_USER": "minioadmin",
|
||||
"MINIO_ROOT_PASSWORD": "minioadmin",
|
||||
},
|
||||
Cmd: []string{"server", "/data"},
|
||||
WaitingFor: wait.ForHTTP("/minio/health/ready").WithPort("9000"),
|
||||
},
|
||||
Started: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer func(c testcontainers.Container, ctx context.Context) {
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := c.Terminate(ctx); err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}(c, ctx)
|
||||
})
|
||||
|
||||
mappedPort, err := c.MappedPort(ctx, "9000")
|
||||
require.NoError(t, err)
|
||||
|
||||
hostIP, err := c.Host(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
awsEndpoint := "http://" + hostIP + ":" + mappedPort.Port()
|
||||
|
||||
t.Setenv("AWS_REGION", awsRegion)
|
||||
t.Setenv("AWS_ENDPOINT_URL", awsEndpoint)
|
||||
t.Setenv("AWS_ACCESS_KEY_ID", "test")
|
||||
t.Setenv("AWS_SECRET_ACCESS_KEY", "test")
|
||||
t.Setenv("AWS_ACCESS_KEY_ID", "minioadmin")
|
||||
t.Setenv("AWS_SECRET_ACCESS_KEY", "minioadmin")
|
||||
t.Setenv("AWS_CONFIG_FILE", "")
|
||||
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "")
|
||||
t.Setenv("AWS_PROFILE", "")
|
||||
|
||||
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion), config.WithBaseEndpoint(awsEndpoint))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cfg, err := config.LoadDefaultConfig(ctx,
|
||||
config.WithRegion(awsRegion),
|
||||
config.WithBaseEndpoint(awsEndpoint),
|
||||
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("minioadmin", "minioadmin", "")),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
o.UsePathStyle = true
|
||||
@@ -66,19 +75,16 @@ func Test_S3HandlerGetUploadURL(t *testing.T) {
|
||||
})
|
||||
|
||||
bucketName := "test"
|
||||
if _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{
|
||||
_, err = client.CreateBucket(ctx, &s3.CreateBucketInput{
|
||||
Bucket: &bucketName,
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
list, err := client.ListBuckets(ctx, &s3.ListBucketsInput{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, len(list.Buckets), 1)
|
||||
assert.Equal(t, *list.Buckets[0].Name, bucketName)
|
||||
require.Len(t, list.Buckets, 1)
|
||||
require.Equal(t, bucketName, *list.Buckets[0].Name)
|
||||
|
||||
t.Setenv(bucketVar, bucketName)
|
||||
|
||||
|
||||
Reference in new issue
Block a user