2022-01-24 11:21:30 +01:00
|
|
|
package idp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2023-03-23 14:54:31 +01:00
|
|
|
|
|
|
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
2022-01-24 11:21:30 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Manager idp manager interface
|
|
|
|
type Manager interface {
|
|
|
|
UpdateUserAppMetadata(userId string, appMetadata AppMetadata) error
|
2022-05-05 08:58:34 +02:00
|
|
|
GetUserDataByID(userId string, appMetadata AppMetadata) (*UserData, error)
|
2022-06-06 12:05:44 +02:00
|
|
|
GetAccount(accountId string) ([]*UserData, error)
|
|
|
|
GetAllAccounts() (map[string][]*UserData, error)
|
2022-10-13 18:26:31 +02:00
|
|
|
CreateUser(email string, name string, accountID string) (*UserData, error)
|
|
|
|
GetUserByEmail(email string) ([]*UserData, error)
|
2022-01-24 11:21:30 +01:00
|
|
|
}
|
|
|
|
|
2023-05-29 13:48:19 +02:00
|
|
|
// ClientConfig defines common client configuration for all IdP manager
|
|
|
|
type ClientConfig struct {
|
2023-05-11 15:14:00 +02:00
|
|
|
Issuer string
|
|
|
|
TokenEndpoint string
|
2023-05-29 13:48:19 +02:00
|
|
|
ClientID string
|
|
|
|
ClientSecret string
|
|
|
|
GrantType string
|
2023-05-11 15:14:00 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 13:48:19 +02:00
|
|
|
// ExtraConfig stores IdP specific config that are unique to individual IdPs
|
|
|
|
type ExtraConfig map[string]string
|
|
|
|
|
2022-01-24 11:21:30 +01:00
|
|
|
// Config an idp configuration struct to be loaded from management server's config file
|
|
|
|
type Config struct {
|
2023-05-29 16:01:04 +02:00
|
|
|
ManagerType string
|
|
|
|
ClientConfig *ClientConfig
|
|
|
|
ExtraConfig ExtraConfig
|
|
|
|
Auth0ClientCredentials Auth0ClientConfig
|
|
|
|
AzureClientCredentials AzureClientConfig
|
|
|
|
KeycloakClientCredentials KeycloakClientConfig
|
|
|
|
ZitadelClientCredentials ZitadelClientConfig
|
2022-01-24 11:21:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ManagerCredentials interface that authenticates using the credential of each type of idp
|
|
|
|
type ManagerCredentials interface {
|
|
|
|
Authenticate() (JWTToken, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ManagerHTTPClient http client interface for API calls
|
|
|
|
type ManagerHTTPClient interface {
|
|
|
|
Do(req *http.Request) (*http.Response, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ManagerHelper helper
|
|
|
|
type ManagerHelper interface {
|
|
|
|
Marshal(v interface{}) ([]byte, error)
|
|
|
|
Unmarshal(data []byte, v interface{}) error
|
|
|
|
}
|
|
|
|
|
2022-05-05 08:58:34 +02:00
|
|
|
type UserData struct {
|
2022-10-13 18:26:31 +02:00
|
|
|
Email string `json:"email"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
ID string `json:"user_id"`
|
|
|
|
AppMetadata AppMetadata `json:"app_metadata"`
|
2022-05-05 08:58:34 +02:00
|
|
|
}
|
|
|
|
|
2022-01-24 11:21:30 +01:00
|
|
|
// AppMetadata user app metadata to associate with a profile
|
|
|
|
type AppMetadata struct {
|
2022-10-13 18:26:31 +02:00
|
|
|
// WTAccountID is a NetBird (previously Wiretrustee) account id to update in the IDP
|
2022-01-24 11:21:30 +01:00
|
|
|
// maps to wt_account_id when json.marshal
|
2022-10-13 18:26:31 +02:00
|
|
|
WTAccountID string `json:"wt_account_id,omitempty"`
|
2022-10-19 17:51:41 +02:00
|
|
|
WTPendingInvite *bool `json:"wt_pending_invite"`
|
2022-01-24 11:21:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// JWTToken a JWT object that holds information of a token
|
|
|
|
type JWTToken struct {
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
ExpiresIn int `json:"expires_in"`
|
|
|
|
expiresInTime time.Time
|
|
|
|
Scope string `json:"scope"`
|
|
|
|
TokenType string `json:"token_type"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewManager returns a new idp manager based on the configuration that it receives
|
2022-10-22 13:29:39 +02:00
|
|
|
func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) {
|
2023-06-02 17:34:36 +02:00
|
|
|
if config.ClientConfig != nil {
|
|
|
|
config.ClientConfig.Issuer = strings.TrimSuffix(config.ClientConfig.Issuer, "/")
|
|
|
|
}
|
|
|
|
|
2022-01-24 11:21:30 +01:00
|
|
|
switch strings.ToLower(config.ManagerType) {
|
|
|
|
case "none", "":
|
|
|
|
return nil, nil
|
|
|
|
case "auth0":
|
2023-05-29 13:48:19 +02:00
|
|
|
auth0ClientConfig := config.Auth0ClientCredentials
|
|
|
|
if config.ClientConfig != nil {
|
|
|
|
auth0ClientConfig = Auth0ClientConfig{
|
|
|
|
Audience: config.ExtraConfig["Audience"],
|
|
|
|
AuthIssuer: config.ClientConfig.Issuer,
|
|
|
|
ClientID: config.ClientConfig.ClientID,
|
|
|
|
ClientSecret: config.ClientConfig.ClientSecret,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewAuth0Manager(auth0ClientConfig, appMetrics)
|
2023-05-03 14:51:44 +02:00
|
|
|
case "azure":
|
2023-05-29 13:48:19 +02:00
|
|
|
azureClientConfig := config.AzureClientCredentials
|
|
|
|
if config.ClientConfig != nil {
|
|
|
|
azureClientConfig = AzureClientConfig{
|
|
|
|
ClientID: config.ClientConfig.ClientID,
|
|
|
|
ClientSecret: config.ClientConfig.ClientSecret,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
|
|
|
TokenEndpoint: config.ClientConfig.TokenEndpoint,
|
2023-06-02 17:34:36 +02:00
|
|
|
ObjectID: config.ExtraConfig["ObjectId"],
|
|
|
|
GraphAPIEndpoint: config.ExtraConfig["GraphApiEndpoint"],
|
2023-05-29 13:48:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewAzureManager(azureClientConfig, appMetrics)
|
2023-03-23 14:54:31 +01:00
|
|
|
case "keycloak":
|
2023-05-29 13:48:19 +02:00
|
|
|
keycloakClientConfig := config.KeycloakClientCredentials
|
|
|
|
if config.ClientConfig != nil {
|
|
|
|
keycloakClientConfig = KeycloakClientConfig{
|
|
|
|
ClientID: config.ClientConfig.ClientID,
|
|
|
|
ClientSecret: config.ClientConfig.ClientSecret,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
|
|
|
TokenEndpoint: config.ClientConfig.TokenEndpoint,
|
|
|
|
AdminEndpoint: config.ExtraConfig["AdminEndpoint"],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewKeycloakManager(keycloakClientConfig, appMetrics)
|
2023-05-05 19:27:28 +02:00
|
|
|
case "zitadel":
|
2023-05-29 13:48:19 +02:00
|
|
|
zitadelClientConfig := config.ZitadelClientCredentials
|
|
|
|
if config.ClientConfig != nil {
|
|
|
|
zitadelClientConfig = ZitadelClientConfig{
|
|
|
|
ClientID: config.ClientConfig.ClientID,
|
|
|
|
ClientSecret: config.ClientConfig.ClientSecret,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
|
|
|
TokenEndpoint: config.ClientConfig.TokenEndpoint,
|
|
|
|
ManagementEndpoint: config.ExtraConfig["ManagementEndpoint"],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewZitadelManager(zitadelClientConfig, appMetrics)
|
2023-05-29 14:35:30 +02:00
|
|
|
case "authentik":
|
2023-05-29 16:01:04 +02:00
|
|
|
authentikConfig := AuthentikClientConfig{
|
|
|
|
Issuer: config.ClientConfig.Issuer,
|
|
|
|
ClientID: config.ClientConfig.ClientID,
|
|
|
|
TokenEndpoint: config.ClientConfig.TokenEndpoint,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
|
|
|
Username: config.ExtraConfig["Username"],
|
|
|
|
Password: config.ExtraConfig["Password"],
|
2023-05-29 14:35:30 +02:00
|
|
|
}
|
|
|
|
return NewAuthentikManager(authentikConfig, appMetrics)
|
2023-05-29 14:52:04 +02:00
|
|
|
case "okta":
|
2023-05-29 16:01:04 +02:00
|
|
|
oktaClientConfig := OktaClientConfig{
|
|
|
|
Issuer: config.ClientConfig.Issuer,
|
|
|
|
TokenEndpoint: config.ClientConfig.TokenEndpoint,
|
|
|
|
GrantType: config.ClientConfig.GrantType,
|
2023-06-02 17:34:36 +02:00
|
|
|
APIToken: config.ExtraConfig["ApiToken"],
|
2023-05-29 14:52:04 +02:00
|
|
|
}
|
|
|
|
return NewOktaManager(oktaClientConfig, appMetrics)
|
|
|
|
|
2022-01-24 11:21:30 +01:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("invalid manager type: %s", config.ManagerType)
|
|
|
|
}
|
|
|
|
}
|