mirror of
https://github.com/netbirdio/netbird
synced 2026-04-22 17:44:57 +02:00
Compare commits
2 Commits
1f89a156b9
...
7fa02e55b3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fa02e55b3 | ||
|
|
12c7faf222 |
@@ -924,19 +924,29 @@ func (p *Provider) GetKeysLocation() string {
|
||||
return issuer + "/keys"
|
||||
}
|
||||
|
||||
// GetClientIDs returns the OAuth2 client IDs configured for this provider.
|
||||
func (p *Provider) GetClientIDs() []string {
|
||||
if p.yamlConfig != nil && len(p.yamlConfig.StaticClients) > 0 {
|
||||
clientIDs := make([]string, 0, len(p.yamlConfig.StaticClients))
|
||||
for _, client := range p.yamlConfig.StaticClients {
|
||||
clientIDs = append(clientIDs, client.ID)
|
||||
}
|
||||
return clientIDs
|
||||
// GetTokenEndpoint returns the OAuth2 token endpoint URL.
|
||||
func (p *Provider) GetTokenEndpoint() string {
|
||||
issuer := p.GetIssuer()
|
||||
if issuer == "" {
|
||||
return ""
|
||||
}
|
||||
// Default client IDs if not configured via YAML
|
||||
return []string{"netbird-dashboard", "netbird-cli"}
|
||||
return issuer + "/token"
|
||||
}
|
||||
|
||||
func (p *Provider) GetUserIDClaim() string {
|
||||
return "sub"
|
||||
// GetDeviceAuthEndpoint returns the OAuth2 device authorization endpoint URL.
|
||||
func (p *Provider) GetDeviceAuthEndpoint() string {
|
||||
issuer := p.GetIssuer()
|
||||
if issuer == "" {
|
||||
return ""
|
||||
}
|
||||
return issuer + "/device/code"
|
||||
}
|
||||
|
||||
// GetAuthorizationEndpoint returns the OAuth2 authorization endpoint URL.
|
||||
func (p *Provider) GetAuthorizationEndpoint() string {
|
||||
issuer := p.GetIssuer()
|
||||
if issuer == "" {
|
||||
return ""
|
||||
}
|
||||
return issuer + "/auth"
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func (s *BaseServer) EventStore() activity.Store {
|
||||
|
||||
func (s *BaseServer) APIHandler() http.Handler {
|
||||
return Create(s, func() http.Handler {
|
||||
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.NetworkMapController())
|
||||
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.NetworkMapController(), s.IdpManager())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create API handler: %v", err)
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func (s *BaseServer) GRPCServer() *grpc.Server {
|
||||
}
|
||||
|
||||
gRPCAPIHandler := grpc.NewServer(gRPCOpts...)
|
||||
srv, err := nbgrpc.NewServer(s.Config, s.AccountManager(), s.SettingsManager(), s.SecretsManager(), s.Metrics(), s.AuthManager(), s.IntegratedValidator(), s.NetworkMapController())
|
||||
srv, err := nbgrpc.NewServer(s.Config, s.AccountManager(), s.SettingsManager(), s.SecretsManager(), s.Metrics(), s.AuthManager(), s.IntegratedValidator(), s.NetworkMapController(), s.OAuthConfigProvider())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create management server: %v", err)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/dexidp/dex/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/netbirdio/netbird/idp/dex"
|
||||
"github.com/netbirdio/netbird/management/server/idp"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
"github.com/netbirdio/netbird/shared/management/client/common"
|
||||
@@ -64,49 +60,7 @@ type Config struct {
|
||||
|
||||
// EmbeddedIdP contains configuration for the embedded Dex OIDC provider.
|
||||
// When set, Dex will be embedded in the management server and serve requests at /oauth2/
|
||||
EmbeddedIdP *EmbeddedIdPConfig
|
||||
}
|
||||
|
||||
// EmbeddedIdPConfig contains configuration for the embedded Dex OIDC identity provider
|
||||
type EmbeddedIdPConfig struct {
|
||||
// Enabled indicates whether the embedded IDP is enabled
|
||||
Enabled bool
|
||||
// Issuer is the OIDC issuer URL (e.g., "http://localhost:3002/oauth2")
|
||||
Issuer string
|
||||
// Storage configuration for the IdP database
|
||||
Storage EmbeddedStorageConfig
|
||||
// DashboardRedirectURIs are the OAuth2 redirect URIs for the dashboard client
|
||||
DashboardRedirectURIs []string
|
||||
// DashboardRedirectURIs are the OAuth2 redirect URIs for the dashboard client
|
||||
CLIRedirectURIs []string
|
||||
// Owner is the initial owner/admin user (optional, can be nil)
|
||||
Owner *OwnerConfig
|
||||
// SignKeyRefreshEnabled enables automatic key rotation for signing keys
|
||||
SignKeyRefreshEnabled bool
|
||||
}
|
||||
|
||||
// EmbeddedStorageConfig holds storage configuration for the embedded IdP.
|
||||
type EmbeddedStorageConfig struct {
|
||||
// Type is the storage type (currently only "sqlite3" is supported)
|
||||
Type string
|
||||
// Config contains type-specific configuration
|
||||
Config EmbeddedStorageTypeConfig
|
||||
}
|
||||
|
||||
// EmbeddedStorageTypeConfig contains type-specific storage configuration.
|
||||
type EmbeddedStorageTypeConfig struct {
|
||||
// File is the path to the SQLite database file (for sqlite3 type)
|
||||
File string
|
||||
}
|
||||
|
||||
// OwnerConfig represents the initial owner/admin user for the embedded IdP.
|
||||
type OwnerConfig struct {
|
||||
// Email is the user's email address (required)
|
||||
Email string
|
||||
// Hash is the bcrypt hash of the user's password (required)
|
||||
Hash string
|
||||
// Username is the display name for the user (optional, defaults to email)
|
||||
Username string
|
||||
EmbeddedIdP *idp.EmbeddedIdPConfig
|
||||
}
|
||||
|
||||
// GetAuthAudiences returns the audience from the http config and device authorization flow config
|
||||
@@ -124,73 +78,6 @@ func (c Config) GetAuthAudiences() []string {
|
||||
return audiences
|
||||
}
|
||||
|
||||
// ToYAMLConfig converts EmbeddedIdPConfig to dex.YAMLConfig.
|
||||
func (c *EmbeddedIdPConfig) ToYAMLConfig() (*dex.YAMLConfig, error) {
|
||||
if c.Issuer == "" {
|
||||
return nil, fmt.Errorf("issuer is required")
|
||||
}
|
||||
if c.Storage.Type == "" {
|
||||
c.Storage.Type = "sqlite3"
|
||||
}
|
||||
if c.Storage.Type == "sqlite3" && c.Storage.Config.File == "" {
|
||||
return nil, fmt.Errorf("storage file is required for sqlite3")
|
||||
}
|
||||
|
||||
cfg := &dex.YAMLConfig{
|
||||
Issuer: c.Issuer,
|
||||
Storage: dex.Storage{
|
||||
Type: c.Storage.Type,
|
||||
Config: map[string]interface{}{
|
||||
"file": c.Storage.Config.File,
|
||||
},
|
||||
},
|
||||
Web: dex.Web{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedHeaders: []string{"Authorization", "Content-Type"},
|
||||
},
|
||||
OAuth2: dex.OAuth2{
|
||||
SkipApprovalScreen: true,
|
||||
},
|
||||
Frontend: dex.Frontend{
|
||||
Issuer: "NetBird",
|
||||
Theme: "light",
|
||||
},
|
||||
EnablePasswordDB: true,
|
||||
StaticClients: []storage.Client{
|
||||
{
|
||||
ID: "netbird-dashboard",
|
||||
Name: "NetBird Dashboard",
|
||||
Public: true,
|
||||
RedirectURIs: c.DashboardRedirectURIs,
|
||||
},
|
||||
{
|
||||
ID: "netbird-cli",
|
||||
Name: "NetBird CLI",
|
||||
Public: true,
|
||||
RedirectURIs: c.CLIRedirectURIs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Add owner user if provided
|
||||
if c.Owner != nil && c.Owner.Email != "" && c.Owner.Hash != "" {
|
||||
username := c.Owner.Username
|
||||
if username == "" {
|
||||
username = c.Owner.Email
|
||||
}
|
||||
cfg.StaticPasswords = []dex.Password{
|
||||
{
|
||||
Email: c.Owner.Email,
|
||||
Hash: []byte(c.Owner.Hash),
|
||||
Username: username,
|
||||
UserID: uuid.New().String(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// TURNConfig is a config of the TURNCredentialsManager
|
||||
type TURNConfig struct {
|
||||
TimeBasedCredentials bool
|
||||
|
||||
@@ -61,17 +61,19 @@ func (s *BaseServer) AuthManager() auth.Manager {
|
||||
signingKeyRefreshEnabled := s.Config.HttpConfig.IdpSignKeyRefreshEnabled
|
||||
issuer := s.Config.HttpConfig.AuthIssuer
|
||||
userIDClaim := s.Config.HttpConfig.AuthUserIDClaim
|
||||
if s.embeddedIdp != nil {
|
||||
// Use embedded IdP provider's methods to extract configuration
|
||||
audiences = s.embeddedIdp.GetClientIDs()
|
||||
|
||||
// Use embedded IdP configuration if available
|
||||
if oauthProvider := s.OAuthConfigProvider(); oauthProvider != nil {
|
||||
audiences = oauthProvider.GetClientIDs()
|
||||
if len(audiences) > 0 {
|
||||
audience = audiences[0] // Use the first client ID as the primary audience
|
||||
}
|
||||
keysLocation = s.embeddedIdp.GetKeysLocation()
|
||||
keysLocation = oauthProvider.GetKeysLocation()
|
||||
signingKeyRefreshEnabled = true
|
||||
issuer = s.embeddedIdp.GetIssuer()
|
||||
userIDClaim = s.embeddedIdp.GetUserIDClaim()
|
||||
issuer = oauthProvider.GetIssuer()
|
||||
userIDClaim = oauthProvider.GetUserIDClaim()
|
||||
}
|
||||
|
||||
return Create(s, func() auth.Manager {
|
||||
return auth.NewManager(s.Store(),
|
||||
issuer,
|
||||
|
||||
@@ -96,10 +96,10 @@ func (s *BaseServer) IdpManager() idp.Manager {
|
||||
var idpManager idp.Manager
|
||||
var err error
|
||||
|
||||
// Use embedded IdP manager if embedded Dex is configured.
|
||||
// Use embedded IdP manager if embedded Dex is configured and enabled.
|
||||
// Legacy IdpManager won't be used anymore even if configured.
|
||||
if s.embeddedIdp != nil {
|
||||
idpManager, err = idp.NewEmbeddedIdPManager(s.embeddedIdp, s.Metrics())
|
||||
if s.Config.EmbeddedIdP != nil && s.Config.EmbeddedIdP.Enabled {
|
||||
idpManager, err = idp.NewEmbeddedIdPManager(context.Background(), s.Config.EmbeddedIdP, s.Metrics())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create embedded IDP manager: %v", err)
|
||||
}
|
||||
@@ -117,6 +117,20 @@ func (s *BaseServer) IdpManager() idp.Manager {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BaseServer) OAuthConfigProvider() idp.OAuthConfigProvider {
|
||||
return Create(s, func() idp.OAuthConfigProvider {
|
||||
if s.Config.EmbeddedIdP == nil || !s.Config.EmbeddedIdP.Enabled {
|
||||
return nil
|
||||
}
|
||||
// Reuse the EmbeddedIdPManager instance from IdpManager
|
||||
// EmbeddedIdPManager implements both idp.Manager and idp.OAuthConfigProvider
|
||||
if provider, ok := s.IdpManager().(idp.OAuthConfigProvider); ok {
|
||||
return provider
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BaseServer) GroupsManager() groups.Manager {
|
||||
return Create(s, func() groups.Manager {
|
||||
return groups.NewManager(s.Store(), s.PermissionsManager(), s.AccountManager())
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/netbirdio/netbird/management/server/idp"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
@@ -19,7 +20,6 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/netbirdio/netbird/encryption"
|
||||
"github.com/netbirdio/netbird/idp/dex"
|
||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
||||
"github.com/netbirdio/netbird/management/server/metrics"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
@@ -63,9 +63,6 @@ type BaseServer struct {
|
||||
certManager *autocert.Manager
|
||||
update *version.Update
|
||||
|
||||
// embeddedIdp is the embedded Dex OIDC identity provider
|
||||
embeddedIdp *dex.Provider
|
||||
|
||||
errCh chan error
|
||||
wg sync.WaitGroup
|
||||
cancel context.CancelFunc
|
||||
@@ -137,19 +134,6 @@ func (s *BaseServer) Start(ctx context.Context) error {
|
||||
go metricsWorker.Run(srvCtx)
|
||||
}
|
||||
|
||||
// Initialize embedded IDP if configured
|
||||
if s.Config.EmbeddedIdP != nil && s.Config.EmbeddedIdP.Enabled {
|
||||
yamlConfig, err := s.Config.EmbeddedIdP.ToYAMLConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create embedded IDP config: %v", err)
|
||||
}
|
||||
s.embeddedIdp, err = dex.NewProviderFromYAML(srvCtx, yamlConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create embedded IDP: %v", err)
|
||||
}
|
||||
log.WithContext(srvCtx).Infof("embedded Dex IDP initialized with issuer: %s", yamlConfig.Issuer)
|
||||
}
|
||||
|
||||
var compatListener net.Listener
|
||||
if s.mgmtPort != ManagementLegacyPort {
|
||||
// The Management gRPC server was running on port 33073 previously. Old agents that are already connected to it
|
||||
@@ -232,8 +216,9 @@ func (s *BaseServer) Stop() error {
|
||||
if s.update != nil {
|
||||
s.update.StopWatch()
|
||||
}
|
||||
if s.embeddedIdp != nil {
|
||||
_ = s.embeddedIdp.Stop(ctx)
|
||||
// Stop embedded IdP if configured
|
||||
if embeddedIdP, ok := s.IdpManager().(*idp.EmbeddedIdPManager); ok {
|
||||
_ = embeddedIdP.Stop(ctx)
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -280,23 +265,6 @@ func (s *BaseServer) handlerFunc(_ context.Context, gRPCHandler *grpc.Server, ht
|
||||
gRPCHandler.ServeHTTP(writer, request)
|
||||
case request.URL.Path == wsproxy.ProxyPath+wsproxy.ManagementComponent:
|
||||
wsProxy.Handler().ServeHTTP(writer, request)
|
||||
case strings.HasPrefix(request.URL.Path, "/oauth2/"):
|
||||
// Add CORS headers for OAuth2 endpoints (needed for browser-based OIDC flows)
|
||||
writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||
writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
|
||||
// Handle preflight OPTIONS request
|
||||
if request.Method == http.MethodOptions {
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if s.embeddedIdp != nil {
|
||||
s.embeddedIdp.Handler().ServeHTTP(writer, request)
|
||||
} else {
|
||||
http.Error(writer, "Embedded IDP not configured", http.StatusNotFound)
|
||||
}
|
||||
default:
|
||||
httpHandler.ServeHTTP(writer, request)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map"
|
||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
||||
"github.com/netbirdio/netbird/management/server/idp"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
@@ -69,6 +70,8 @@ type Server struct {
|
||||
|
||||
networkMapController network_map.Controller
|
||||
|
||||
oAuthConfigProvider idp.OAuthConfigProvider
|
||||
|
||||
syncSem atomic.Int32
|
||||
syncLim int32
|
||||
}
|
||||
@@ -83,6 +86,7 @@ func NewServer(
|
||||
authManager auth.Manager,
|
||||
integratedPeerValidator integrated_validator.IntegratedValidator,
|
||||
networkMapController network_map.Controller,
|
||||
oAuthConfigProvider idp.OAuthConfigProvider,
|
||||
) (*Server, error) {
|
||||
if appMetrics != nil {
|
||||
// update gauge based on number of connected peers which is equal to open gRPC streams
|
||||
@@ -119,6 +123,7 @@ func NewServer(
|
||||
blockPeersWithSameConfig: blockPeersWithSameConfig,
|
||||
integratedPeerValidator: integratedPeerValidator,
|
||||
networkMapController: networkMapController,
|
||||
oAuthConfigProvider: oAuthConfigProvider,
|
||||
|
||||
loginFilter: newLoginFilter(),
|
||||
|
||||
@@ -752,32 +757,49 @@ func (s *Server) GetDeviceAuthorizationFlow(ctx context.Context, req *proto.Encr
|
||||
return nil, status.Error(codes.InvalidArgument, errMSG)
|
||||
}
|
||||
|
||||
if s.config.DeviceAuthorizationFlow == nil || s.config.DeviceAuthorizationFlow.Provider == string(nbconfig.NONE) {
|
||||
return nil, status.Error(codes.NotFound, "no device authorization flow information available")
|
||||
}
|
||||
var flowInfoResp *proto.DeviceAuthorizationFlow
|
||||
|
||||
provider, ok := proto.DeviceAuthorizationFlowProvider_value[strings.ToUpper(s.config.DeviceAuthorizationFlow.Provider)]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "no provider found in the protocol for %s", s.config.DeviceAuthorizationFlow.Provider)
|
||||
}
|
||||
// Use embedded IdP configuration if available
|
||||
if s.oAuthConfigProvider != nil {
|
||||
flowInfoResp = &proto.DeviceAuthorizationFlow{
|
||||
Provider: proto.DeviceAuthorizationFlow_HOSTED,
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
ClientID: s.oAuthConfigProvider.GetCLIClientID(),
|
||||
Audience: s.oAuthConfigProvider.GetCLIClientID(),
|
||||
DeviceAuthEndpoint: s.oAuthConfigProvider.GetDeviceAuthEndpoint(),
|
||||
TokenEndpoint: s.oAuthConfigProvider.GetTokenEndpoint(),
|
||||
Scope: s.oAuthConfigProvider.GetDefaultScopes(),
|
||||
UseIDToken: true,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
if s.config.DeviceAuthorizationFlow == nil || s.config.DeviceAuthorizationFlow.Provider == string(nbconfig.NONE) {
|
||||
return nil, status.Error(codes.NotFound, "no device authorization flow information available")
|
||||
}
|
||||
|
||||
flowInfoResp := &proto.DeviceAuthorizationFlow{
|
||||
Provider: proto.DeviceAuthorizationFlowProvider(provider),
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
ClientID: s.config.DeviceAuthorizationFlow.ProviderConfig.ClientID,
|
||||
ClientSecret: s.config.DeviceAuthorizationFlow.ProviderConfig.ClientSecret,
|
||||
Domain: s.config.DeviceAuthorizationFlow.ProviderConfig.Domain,
|
||||
Audience: s.config.DeviceAuthorizationFlow.ProviderConfig.Audience,
|
||||
DeviceAuthEndpoint: s.config.DeviceAuthorizationFlow.ProviderConfig.DeviceAuthEndpoint,
|
||||
TokenEndpoint: s.config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint,
|
||||
Scope: s.config.DeviceAuthorizationFlow.ProviderConfig.Scope,
|
||||
UseIDToken: s.config.DeviceAuthorizationFlow.ProviderConfig.UseIDToken,
|
||||
},
|
||||
provider, ok := proto.DeviceAuthorizationFlowProvider_value[strings.ToUpper(s.config.DeviceAuthorizationFlow.Provider)]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "no provider found in the protocol for %s", s.config.DeviceAuthorizationFlow.Provider)
|
||||
}
|
||||
|
||||
flowInfoResp = &proto.DeviceAuthorizationFlow{
|
||||
Provider: proto.DeviceAuthorizationFlowProvider(provider),
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
ClientID: s.config.DeviceAuthorizationFlow.ProviderConfig.ClientID,
|
||||
ClientSecret: s.config.DeviceAuthorizationFlow.ProviderConfig.ClientSecret,
|
||||
Domain: s.config.DeviceAuthorizationFlow.ProviderConfig.Domain,
|
||||
Audience: s.config.DeviceAuthorizationFlow.ProviderConfig.Audience,
|
||||
DeviceAuthEndpoint: s.config.DeviceAuthorizationFlow.ProviderConfig.DeviceAuthEndpoint,
|
||||
TokenEndpoint: s.config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint,
|
||||
Scope: s.config.DeviceAuthorizationFlow.ProviderConfig.Scope,
|
||||
UseIDToken: s.config.DeviceAuthorizationFlow.ProviderConfig.UseIDToken,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, key, flowInfoResp)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "failed to encrypt no device authorization flow information")
|
||||
return nil, status.Error(codes.Internal, "failed to encrypt device authorization flow information")
|
||||
}
|
||||
|
||||
return &proto.EncryptedMessage{
|
||||
@@ -811,30 +833,47 @@ func (s *Server) GetPKCEAuthorizationFlow(ctx context.Context, req *proto.Encryp
|
||||
return nil, status.Error(codes.InvalidArgument, errMSG)
|
||||
}
|
||||
|
||||
if s.config.PKCEAuthorizationFlow == nil {
|
||||
return nil, status.Error(codes.NotFound, "no pkce authorization flow information available")
|
||||
}
|
||||
var initInfoFlow *proto.PKCEAuthorizationFlow
|
||||
|
||||
initInfoFlow := &proto.PKCEAuthorizationFlow{
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
Audience: s.config.PKCEAuthorizationFlow.ProviderConfig.Audience,
|
||||
ClientID: s.config.PKCEAuthorizationFlow.ProviderConfig.ClientID,
|
||||
ClientSecret: s.config.PKCEAuthorizationFlow.ProviderConfig.ClientSecret,
|
||||
TokenEndpoint: s.config.PKCEAuthorizationFlow.ProviderConfig.TokenEndpoint,
|
||||
AuthorizationEndpoint: s.config.PKCEAuthorizationFlow.ProviderConfig.AuthorizationEndpoint,
|
||||
Scope: s.config.PKCEAuthorizationFlow.ProviderConfig.Scope,
|
||||
RedirectURLs: s.config.PKCEAuthorizationFlow.ProviderConfig.RedirectURLs,
|
||||
UseIDToken: s.config.PKCEAuthorizationFlow.ProviderConfig.UseIDToken,
|
||||
DisablePromptLogin: s.config.PKCEAuthorizationFlow.ProviderConfig.DisablePromptLogin,
|
||||
LoginFlag: uint32(s.config.PKCEAuthorizationFlow.ProviderConfig.LoginFlag),
|
||||
},
|
||||
// Use embedded IdP configuration if available
|
||||
if s.oAuthConfigProvider != nil {
|
||||
initInfoFlow = &proto.PKCEAuthorizationFlow{
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
Audience: s.oAuthConfigProvider.GetCLIClientID(),
|
||||
ClientID: s.oAuthConfigProvider.GetCLIClientID(),
|
||||
TokenEndpoint: s.oAuthConfigProvider.GetTokenEndpoint(),
|
||||
AuthorizationEndpoint: s.oAuthConfigProvider.GetAuthorizationEndpoint(),
|
||||
Scope: s.oAuthConfigProvider.GetDefaultScopes(),
|
||||
RedirectURLs: s.oAuthConfigProvider.GetCLIRedirectURLs(),
|
||||
UseIDToken: true,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
if s.config.PKCEAuthorizationFlow == nil {
|
||||
return nil, status.Error(codes.NotFound, "no pkce authorization flow information available")
|
||||
}
|
||||
|
||||
initInfoFlow = &proto.PKCEAuthorizationFlow{
|
||||
ProviderConfig: &proto.ProviderConfig{
|
||||
Audience: s.config.PKCEAuthorizationFlow.ProviderConfig.Audience,
|
||||
ClientID: s.config.PKCEAuthorizationFlow.ProviderConfig.ClientID,
|
||||
ClientSecret: s.config.PKCEAuthorizationFlow.ProviderConfig.ClientSecret,
|
||||
TokenEndpoint: s.config.PKCEAuthorizationFlow.ProviderConfig.TokenEndpoint,
|
||||
AuthorizationEndpoint: s.config.PKCEAuthorizationFlow.ProviderConfig.AuthorizationEndpoint,
|
||||
Scope: s.config.PKCEAuthorizationFlow.ProviderConfig.Scope,
|
||||
RedirectURLs: s.config.PKCEAuthorizationFlow.ProviderConfig.RedirectURLs,
|
||||
UseIDToken: s.config.PKCEAuthorizationFlow.ProviderConfig.UseIDToken,
|
||||
DisablePromptLogin: s.config.PKCEAuthorizationFlow.ProviderConfig.DisablePromptLogin,
|
||||
LoginFlag: uint32(s.config.PKCEAuthorizationFlow.ProviderConfig.LoginFlag),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
flowInfoResp := s.integratedPeerValidator.ValidateFlowResponse(ctx, peerKey.String(), initInfoFlow)
|
||||
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, key, flowInfoResp)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "failed to encrypt no pkce authorization flow information")
|
||||
return nil, status.Error(codes.Internal, "failed to encrypt pkce authorization flow information")
|
||||
}
|
||||
|
||||
return &proto.EncryptedMessage{
|
||||
|
||||
@@ -243,7 +243,7 @@ func BuildManager(
|
||||
am.externalCacheManager = nbcache.NewUserDataCache(cacheStore)
|
||||
am.cacheManager = nbcache.NewAccountUserDataCache(am.loadAccount, cacheStore)
|
||||
|
||||
if !isNil(am.idpManager) && !isEmbeddedIdp(am.idpManager) {
|
||||
if !IsNil(am.idpManager) && !IsEmbeddedIdp(am.idpManager) {
|
||||
go func() {
|
||||
err := am.warmupIDPCache(ctx, cacheStore)
|
||||
if err != nil {
|
||||
@@ -763,14 +763,14 @@ func (am *DefaultAccountManager) GetAccountIDByUserID(ctx context.Context, userI
|
||||
return accountID, nil
|
||||
}
|
||||
|
||||
func isNil(i idp.Manager) bool {
|
||||
func IsNil(i idp.Manager) bool {
|
||||
return i == nil || reflect.ValueOf(i).IsNil()
|
||||
}
|
||||
|
||||
// isEmbeddedIdp checks if the IDP manager is an embedded IDP (data stored locally in DB).
|
||||
// IsEmbeddedIdp checks if the IDP manager is an embedded IDP (data stored locally in DB).
|
||||
// When true, user cache should be skipped and data fetched directly from the IDP manager.
|
||||
func isEmbeddedIdp(i idp.Manager) bool {
|
||||
if isNil(i) {
|
||||
func IsEmbeddedIdp(i idp.Manager) bool {
|
||||
if IsNil(i) {
|
||||
return false
|
||||
}
|
||||
_, ok := i.(*idp.EmbeddedIdPManager)
|
||||
@@ -779,7 +779,7 @@ func isEmbeddedIdp(i idp.Manager) bool {
|
||||
|
||||
// addAccountIDToIDPAppMeta update user's app metadata in idp manager
|
||||
func (am *DefaultAccountManager) addAccountIDToIDPAppMeta(ctx context.Context, userID string, accountID string) error {
|
||||
if !isNil(am.idpManager) && !isEmbeddedIdp(am.idpManager) {
|
||||
if !IsNil(am.idpManager) && !IsEmbeddedIdp(am.idpManager) {
|
||||
// user can be nil if it wasn't found (e.g., just created)
|
||||
user, err := am.lookupUserInCache(ctx, userID, accountID)
|
||||
if err != nil {
|
||||
@@ -1025,7 +1025,7 @@ func (am *DefaultAccountManager) isCacheFresh(ctx context.Context, accountUsers
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) removeUserFromCache(ctx context.Context, accountID, userID string) error {
|
||||
if isEmbeddedIdp(am.idpManager) {
|
||||
if IsEmbeddedIdp(am.idpManager) {
|
||||
return nil
|
||||
}
|
||||
data, err := am.getAccountFromCache(ctx, accountID, false)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
||||
"github.com/rs/cors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@@ -52,23 +53,7 @@ const (
|
||||
)
|
||||
|
||||
// NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
||||
func NewAPIHandler(
|
||||
ctx context.Context,
|
||||
accountManager account.Manager,
|
||||
networksManager nbnetworks.Manager,
|
||||
resourceManager resources.Manager,
|
||||
routerManager routers.Manager,
|
||||
groupsManager nbgroups.Manager,
|
||||
LocationManager geolocation.Geolocation,
|
||||
authManager auth.Manager,
|
||||
appMetrics telemetry.AppMetrics,
|
||||
integratedValidator integrated_validator.IntegratedValidator,
|
||||
proxyController port_forwarding.Controller,
|
||||
permissionsManager permissions.Manager,
|
||||
peersManager nbpeers.Manager,
|
||||
settingsManager settings.Manager,
|
||||
networkMapController network_map.Controller,
|
||||
) (http.Handler, error) {
|
||||
func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager) (http.Handler, error) {
|
||||
|
||||
var rateLimitingConfig *middleware.RateLimiterConfig
|
||||
if os.Getenv(rateLimitingEnabledKey) == "true" {
|
||||
@@ -137,5 +122,10 @@ func NewAPIHandler(
|
||||
networks.AddEndpoints(networksManager, resourceManager, routerManager, groupsManager, accountManager, router)
|
||||
idp.AddEndpoints(accountManager, router)
|
||||
|
||||
// Mount embedded IdP handler at /oauth2 path if configured
|
||||
if embeddedIdP, ok := idpManager.(*idpmanager.EmbeddedIdPManager); ok {
|
||||
rootRouter.PathPrefix("/oauth2").Handler(corsMiddleware.Handler(embeddedIdP.Handler()))
|
||||
}
|
||||
|
||||
return rootRouter, nil
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func BuildApiBlackBoxWithDBState(t testing_tools.TB, sqlFile string, expectedPee
|
||||
groupsManagerMock := groups.NewManagerMock()
|
||||
peersManager := peers.NewManager(store, permissionsManager)
|
||||
|
||||
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, networkMapController)
|
||||
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, networkMapController, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create API handler: %v", err)
|
||||
}
|
||||
|
||||
@@ -4,35 +4,207 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/dexidp/dex/storage"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/idp/dex"
|
||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||
)
|
||||
|
||||
const (
|
||||
staticClientDashboard = "netbird-dashboard"
|
||||
staticClientCLI = "netbird-cli"
|
||||
defaultCLIRedirectURL1 = "http://localhost:53000/"
|
||||
defaultCLIRedirectURL2 = "http://localhost:54000/"
|
||||
defaultScopes = "openid profile email offline_access"
|
||||
defaultUserIDClaim = "sub"
|
||||
)
|
||||
|
||||
// EmbeddedIdPConfig contains configuration for the embedded Dex OIDC identity provider
|
||||
type EmbeddedIdPConfig struct {
|
||||
// Enabled indicates whether the embedded IDP is enabled
|
||||
Enabled bool
|
||||
// Issuer is the OIDC issuer URL (e.g., "http://localhost:3002/oauth2")
|
||||
Issuer string
|
||||
// Storage configuration for the IdP database
|
||||
Storage EmbeddedStorageConfig
|
||||
// DashboardRedirectURIs are the OAuth2 redirect URIs for the dashboard client
|
||||
DashboardRedirectURIs []string
|
||||
// DashboardRedirectURIs are the OAuth2 redirect URIs for the dashboard client
|
||||
CLIRedirectURIs []string
|
||||
// Owner is the initial owner/admin user (optional, can be nil)
|
||||
Owner *OwnerConfig
|
||||
// SignKeyRefreshEnabled enables automatic key rotation for signing keys
|
||||
SignKeyRefreshEnabled bool
|
||||
}
|
||||
|
||||
// EmbeddedStorageConfig holds storage configuration for the embedded IdP.
|
||||
type EmbeddedStorageConfig struct {
|
||||
// Type is the storage type (currently only "sqlite3" is supported)
|
||||
Type string
|
||||
// Config contains type-specific configuration
|
||||
Config EmbeddedStorageTypeConfig
|
||||
}
|
||||
|
||||
// EmbeddedStorageTypeConfig contains type-specific storage configuration.
|
||||
type EmbeddedStorageTypeConfig struct {
|
||||
// File is the path to the SQLite database file (for sqlite3 type)
|
||||
File string
|
||||
}
|
||||
|
||||
// OwnerConfig represents the initial owner/admin user for the embedded IdP.
|
||||
type OwnerConfig struct {
|
||||
// Email is the user's email address (required)
|
||||
Email string
|
||||
// Hash is the bcrypt hash of the user's password (required)
|
||||
Hash string
|
||||
// Username is the display name for the user (optional, defaults to email)
|
||||
Username string
|
||||
}
|
||||
|
||||
// ToYAMLConfig converts EmbeddedIdPConfig to dex.YAMLConfig.
|
||||
func (c *EmbeddedIdPConfig) ToYAMLConfig() (*dex.YAMLConfig, error) {
|
||||
if c.Issuer == "" {
|
||||
return nil, fmt.Errorf("issuer is required")
|
||||
}
|
||||
if c.Storage.Type == "" {
|
||||
c.Storage.Type = "sqlite3"
|
||||
}
|
||||
if c.Storage.Type == "sqlite3" && c.Storage.Config.File == "" {
|
||||
return nil, fmt.Errorf("storage file is required for sqlite3")
|
||||
}
|
||||
|
||||
// Build CLI redirect URIs including the device callback (both relative and absolute)
|
||||
cliRedirectURIs := c.CLIRedirectURIs
|
||||
cliRedirectURIs = append(cliRedirectURIs, "/device/callback")
|
||||
cliRedirectURIs = append(cliRedirectURIs, c.Issuer+"/device/callback")
|
||||
|
||||
cfg := &dex.YAMLConfig{
|
||||
Issuer: c.Issuer,
|
||||
Storage: dex.Storage{
|
||||
Type: c.Storage.Type,
|
||||
Config: map[string]interface{}{
|
||||
"file": c.Storage.Config.File,
|
||||
},
|
||||
},
|
||||
Web: dex.Web{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedHeaders: []string{"Authorization", "Content-Type"},
|
||||
},
|
||||
OAuth2: dex.OAuth2{
|
||||
SkipApprovalScreen: true,
|
||||
},
|
||||
Frontend: dex.Frontend{
|
||||
Issuer: "NetBird",
|
||||
Theme: "light",
|
||||
},
|
||||
EnablePasswordDB: true,
|
||||
StaticClients: []storage.Client{
|
||||
{
|
||||
ID: staticClientDashboard,
|
||||
Name: "NetBird Dashboard",
|
||||
Public: true,
|
||||
RedirectURIs: c.DashboardRedirectURIs,
|
||||
},
|
||||
{
|
||||
ID: staticClientCLI,
|
||||
Name: "NetBird CLI",
|
||||
Public: true,
|
||||
RedirectURIs: cliRedirectURIs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Add owner user if provided
|
||||
if c.Owner != nil && c.Owner.Email != "" && c.Owner.Hash != "" {
|
||||
username := c.Owner.Username
|
||||
if username == "" {
|
||||
username = c.Owner.Email
|
||||
}
|
||||
cfg.StaticPasswords = []dex.Password{
|
||||
{
|
||||
Email: c.Owner.Email,
|
||||
Hash: []byte(c.Owner.Hash),
|
||||
Username: username,
|
||||
UserID: uuid.New().String(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Compile-time check that EmbeddedIdPManager implements Manager interface
|
||||
var _ Manager = (*EmbeddedIdPManager)(nil)
|
||||
|
||||
// Compile-time check that EmbeddedIdPManager implements OAuthConfigProvider interface
|
||||
var _ OAuthConfigProvider = (*EmbeddedIdPManager)(nil)
|
||||
|
||||
// OAuthConfigProvider defines the interface for OAuth configuration needed by auth flows.
|
||||
type OAuthConfigProvider interface {
|
||||
GetIssuer() string
|
||||
GetKeysLocation() string
|
||||
GetClientIDs() []string
|
||||
GetUserIDClaim() string
|
||||
GetTokenEndpoint() string
|
||||
GetDeviceAuthEndpoint() string
|
||||
GetAuthorizationEndpoint() string
|
||||
GetDefaultScopes() string
|
||||
GetCLIClientID() string
|
||||
GetCLIRedirectURLs() []string
|
||||
}
|
||||
|
||||
// EmbeddedIdPManager implements the Manager interface using the embedded Dex IdP.
|
||||
type EmbeddedIdPManager struct {
|
||||
provider *dex.Provider
|
||||
appMetrics telemetry.AppMetrics
|
||||
config EmbeddedIdPConfig
|
||||
}
|
||||
|
||||
// NewEmbeddedIdPManager creates a new instance of EmbeddedIdPManager with an existing provider.
|
||||
func NewEmbeddedIdPManager(provider *dex.Provider, appMetrics telemetry.AppMetrics) (*EmbeddedIdPManager, error) {
|
||||
if provider == nil {
|
||||
return nil, fmt.Errorf("embedded IdP provider is required")
|
||||
// NewEmbeddedIdPManager creates a new instance of EmbeddedIdPManager from a configuration.
|
||||
// It instantiates the underlying Dex provider internally.
|
||||
func NewEmbeddedIdPManager(ctx context.Context, config *EmbeddedIdPConfig, appMetrics telemetry.AppMetrics) (*EmbeddedIdPManager, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("embedded IdP config is required")
|
||||
}
|
||||
|
||||
if len(config.CLIRedirectURIs) == 0 {
|
||||
config.CLIRedirectURIs = []string{defaultCLIRedirectURL1, defaultCLIRedirectURL2}
|
||||
}
|
||||
|
||||
// there are some properties create when creating YAML config (e.g., auth clients)
|
||||
yamlConfig, err := config.ToYAMLConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
provider, err := dex.NewProviderFromYAML(ctx, yamlConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create embedded IdP provider: %w", err)
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Infof("embedded Dex IDP initialized with issuer: %s", yamlConfig.Issuer)
|
||||
|
||||
return &EmbeddedIdPManager{
|
||||
provider: provider,
|
||||
appMetrics: appMetrics,
|
||||
config: *config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handler returns the HTTP handler for serving OIDC requests.
|
||||
func (m *EmbeddedIdPManager) Handler() http.Handler {
|
||||
return m.provider.Handler()
|
||||
}
|
||||
|
||||
// Stop gracefully shuts down the embedded IdP provider.
|
||||
func (m *EmbeddedIdPManager) Stop(ctx context.Context) error {
|
||||
return m.provider.Stop(ctx)
|
||||
}
|
||||
|
||||
// UpdateUserAppMetadata updates user app metadata based on userID and metadata map.
|
||||
func (m *EmbeddedIdPManager) UpdateUserAppMetadata(ctx context.Context, userID string, appMetadata AppMetadata) error {
|
||||
// TODO: implement
|
||||
@@ -237,7 +409,55 @@ func (m *EmbeddedIdPManager) DeleteConnector(ctx context.Context, id string) err
|
||||
return m.provider.DeleteConnector(ctx, id)
|
||||
}
|
||||
|
||||
// GetRedirectURI returns the Dex callback redirect URI for configuring connectors.
|
||||
func (m *EmbeddedIdPManager) GetRedirectURI() string {
|
||||
return m.provider.GetRedirectURI()
|
||||
// GetIssuer returns the OIDC issuer URL.
|
||||
func (m *EmbeddedIdPManager) GetIssuer() string {
|
||||
return m.provider.GetIssuer()
|
||||
}
|
||||
|
||||
// GetTokenEndpoint returns the OAuth2 token endpoint URL.
|
||||
func (m *EmbeddedIdPManager) GetTokenEndpoint() string {
|
||||
return m.provider.GetTokenEndpoint()
|
||||
}
|
||||
|
||||
// GetDeviceAuthEndpoint returns the OAuth2 device authorization endpoint URL.
|
||||
func (m *EmbeddedIdPManager) GetDeviceAuthEndpoint() string {
|
||||
return m.provider.GetDeviceAuthEndpoint()
|
||||
}
|
||||
|
||||
// GetAuthorizationEndpoint returns the OAuth2 authorization endpoint URL.
|
||||
func (m *EmbeddedIdPManager) GetAuthorizationEndpoint() string {
|
||||
return m.provider.GetAuthorizationEndpoint()
|
||||
}
|
||||
|
||||
// GetDefaultScopes returns the default OAuth2 scopes for authentication.
|
||||
func (m *EmbeddedIdPManager) GetDefaultScopes() string {
|
||||
return defaultScopes
|
||||
}
|
||||
|
||||
// GetCLIClientID returns the client ID for CLI authentication.
|
||||
func (m *EmbeddedIdPManager) GetCLIClientID() string {
|
||||
return staticClientCLI
|
||||
}
|
||||
|
||||
// GetCLIRedirectURLs returns the redirect URLs configured for the CLI client.
|
||||
func (m *EmbeddedIdPManager) GetCLIRedirectURLs() []string {
|
||||
if len(m.config.CLIRedirectURIs) == 0 {
|
||||
return []string{defaultCLIRedirectURL1, defaultCLIRedirectURL2}
|
||||
}
|
||||
return m.config.CLIRedirectURIs
|
||||
}
|
||||
|
||||
// GetKeysLocation returns the JWKS endpoint URL for token validation.
|
||||
func (m *EmbeddedIdPManager) GetKeysLocation() string {
|
||||
return m.provider.GetKeysLocation()
|
||||
}
|
||||
|
||||
// GetClientIDs returns the OAuth2 client IDs configured for this provider.
|
||||
func (m *EmbeddedIdPManager) GetClientIDs() []string {
|
||||
return []string{staticClientDashboard, staticClientCLI}
|
||||
}
|
||||
|
||||
// GetUserIDClaim returns the JWT claim name used for user identification.
|
||||
func (m *EmbeddedIdPManager) GetUserIDClaim() string {
|
||||
return defaultUserIDClaim
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, u
|
||||
}
|
||||
|
||||
var idpUser *idp.UserData
|
||||
if isEmbeddedIdp(am.idpManager) {
|
||||
if IsEmbeddedIdp(am.idpManager) {
|
||||
idpUser, err = am.createEmbeddedIdpUser(ctx, accountID, inviterID, invite)
|
||||
} else {
|
||||
idpUser, err = am.createNewIdpUser(ctx, accountID, inviterID, invite)
|
||||
@@ -131,7 +131,7 @@ func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, u
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isEmbeddedIdp(am.idpManager) {
|
||||
if !IsEmbeddedIdp(am.idpManager) {
|
||||
_, err = am.refreshCache(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -799,7 +799,7 @@ func handleOwnerRoleTransfer(ctx context.Context, transaction store.Store, initi
|
||||
// If the AccountManager has a non-nil idpManager and the User is not a service user,
|
||||
// it will attempt to look up the UserData from the cache.
|
||||
func (am *DefaultAccountManager) getUserInfo(ctx context.Context, user *types.User, accountID string) (*types.UserInfo, error) {
|
||||
if !isNil(am.idpManager) && !user.IsServiceUser && !isEmbeddedIdp(am.idpManager) {
|
||||
if !IsNil(am.idpManager) && !user.IsServiceUser && !IsEmbeddedIdp(am.idpManager) {
|
||||
userData, err := am.lookupUserInCache(ctx, user.Id, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -927,7 +927,7 @@ func (am *DefaultAccountManager) BuildUserInfosForAccount(ctx context.Context, a
|
||||
var err error
|
||||
|
||||
// embedded IdP ensures that we have user data (email and name) stored in the database.
|
||||
if !isNil(am.idpManager) && !isEmbeddedIdp(am.idpManager) {
|
||||
if !IsNil(am.idpManager) && !IsEmbeddedIdp(am.idpManager) {
|
||||
users := make(map[string]userLoggedInOnce, len(accountUsers))
|
||||
usersFromIntegration := make([]*idp.UserData, 0)
|
||||
for _, user := range accountUsers {
|
||||
@@ -1139,7 +1139,7 @@ func (am *DefaultAccountManager) DeleteRegularUsers(ctx context.Context, account
|
||||
|
||||
// deleteRegularUser deletes a specified user and their related peers from the account.
|
||||
func (am *DefaultAccountManager) deleteRegularUser(ctx context.Context, accountID, initiatorUserID string, targetUserInfo *types.UserInfo) (bool, error) {
|
||||
if !isNil(am.idpManager) {
|
||||
if !IsNil(am.idpManager) {
|
||||
// Delete if the user already exists in the IdP. Necessary in cases where a user account
|
||||
// was created where a user account was provisioned but the user did not sign in
|
||||
_, err := am.idpManager.GetUserDataByID(ctx, targetUserInfo.ID, idp.AppMetadata{WTAccountID: accountID})
|
||||
|
||||
Reference in New Issue
Block a user