mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-04 05:53:18 +01:00
7794b744f8
Enhance the user experience by enabling authentication to Netbird using Single Sign-On (SSO) with any Identity Provider (IDP) provider. Current client offers this capability through the Device Authorization Flow, however, is not widely supported by many IDPs, and even some that do support it do not provide a complete verification URL. To address these challenges, this pull request enable Authorization Code Flow with Proof Key for Code Exchange (PKCE) for client logins, which is a more widely adopted and secure approach to facilitate SSO with various IDP providers.
91 lines
3.1 KiB
Go
91 lines
3.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc/codes"
|
|
gstatus "google.golang.org/grpc/status"
|
|
|
|
"github.com/netbirdio/netbird/client/internal"
|
|
)
|
|
|
|
// OAuthFlow represents an interface for authorization using different OAuth 2.0 flows
|
|
type OAuthFlow interface {
|
|
RequestAuthInfo(ctx context.Context) (AuthFlowInfo, error)
|
|
WaitToken(ctx context.Context, info AuthFlowInfo) (TokenInfo, error)
|
|
GetClientID(ctx context.Context) string
|
|
}
|
|
|
|
// HTTPClient http client interface for API calls
|
|
type HTTPClient interface {
|
|
Do(req *http.Request) (*http.Response, error)
|
|
}
|
|
|
|
// AuthFlowInfo holds information for the OAuth 2.0 authorization flow
|
|
type AuthFlowInfo struct {
|
|
DeviceCode string `json:"device_code"`
|
|
UserCode string `json:"user_code"`
|
|
VerificationURI string `json:"verification_uri"`
|
|
VerificationURIComplete string `json:"verification_uri_complete"`
|
|
ExpiresIn int `json:"expires_in"`
|
|
Interval int `json:"interval"`
|
|
}
|
|
|
|
// Claims used when validating the access token
|
|
type Claims struct {
|
|
Audience interface{} `json:"aud"`
|
|
}
|
|
|
|
// TokenInfo holds information of issued access token
|
|
type TokenInfo struct {
|
|
AccessToken string `json:"access_token"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
IDToken string `json:"id_token"`
|
|
TokenType string `json:"token_type"`
|
|
ExpiresIn int `json:"expires_in"`
|
|
UseIDToken bool `json:"-"`
|
|
}
|
|
|
|
// GetTokenToUse returns either the access or id token based on UseIDToken field
|
|
func (t TokenInfo) GetTokenToUse() string {
|
|
if t.UseIDToken {
|
|
return t.IDToken
|
|
}
|
|
return t.AccessToken
|
|
}
|
|
|
|
// NewOAuthFlow initializes and returns the appropriate OAuth flow based on the management configuration.
|
|
func NewOAuthFlow(ctx context.Context, config *internal.Config) (OAuthFlow, error) {
|
|
log.Debug("getting device authorization flow info")
|
|
|
|
// Try to initialize the Device Authorization Flow
|
|
deviceFlowInfo, err := internal.GetDeviceAuthorizationFlowInfo(ctx, config.PrivateKey, config.ManagementURL)
|
|
if err == nil {
|
|
return NewDeviceAuthorizationFlow(deviceFlowInfo.ProviderConfig)
|
|
}
|
|
|
|
log.Debugf("getting device authorization flow info failed with error: %v", err)
|
|
log.Debugf("falling back to pkce authorization flow info")
|
|
|
|
// If Device Authorization Flow failed, try the PKCE Authorization Flow
|
|
pkceFlowInfo, err := internal.GetPKCEAuthorizationFlowInfo(ctx, config.PrivateKey, config.ManagementURL)
|
|
if err != nil {
|
|
s, ok := gstatus.FromError(err)
|
|
if ok && s.Code() == codes.NotFound {
|
|
return nil, fmt.Errorf("no SSO provider returned from management. " +
|
|
"If you are using hosting Netbird see documentation at " +
|
|
"https://github.com/netbirdio/netbird/tree/main/management for details")
|
|
} else if ok && s.Code() == codes.Unimplemented {
|
|
return nil, fmt.Errorf("the management server, %s, does not support SSO providers, "+
|
|
"please update your server or use Setup Keys to login", config.ManagementURL)
|
|
} else {
|
|
return nil, fmt.Errorf("getting pkce authorization flow info failed with error: %v", err)
|
|
}
|
|
}
|
|
|
|
return NewPKCEAuthorizationFlow(pkceFlowInfo.ProviderConfig)
|
|
}
|