mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-20 20:39:08 +02:00
Client Login via device authorization flow (#309)
UI and CLI Clients are now able to use SSO login by default we will check if the management has configured or supports SSO providers daemon will handle fetching and waiting for an access token Oauth package was moved to internal to avoid one extra package at this stage Secrets were removed from OAuth CLI clients have less and better output 2 new status were introduced, NeedsLogin and FailedLogin for better messaging With NeedsLogin we no longer have endless login attempts
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
mgm "github.com/netbirdio/netbird/management/client"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
@@ -83,6 +87,10 @@ func parseURL(serviceName, managementURL string) (*url.URL, error) {
|
||||
// ReadConfig reads existing config. In case provided managementURL is not empty overrides the read property
|
||||
func ReadConfig(managementURL, adminURL, configPath string, preSharedKey *string) (*Config, error) {
|
||||
config := &Config{}
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
return nil, status.Errorf(codes.NotFound, "config file doesn't exist")
|
||||
}
|
||||
|
||||
if _, err := util.ReadJson(configPath, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -151,3 +159,77 @@ func generateKey() string {
|
||||
}
|
||||
return key.String()
|
||||
}
|
||||
|
||||
// DeviceAuthorizationFlow represents Device Authorization Flow information
|
||||
type DeviceAuthorizationFlow struct {
|
||||
Provider string
|
||||
ProviderConfig ProviderConfig
|
||||
}
|
||||
|
||||
// ProviderConfig has all attributes needed to initiate a device authorization flow
|
||||
type ProviderConfig struct {
|
||||
// ClientID An IDP application client id
|
||||
ClientID string
|
||||
// ClientSecret An IDP application client secret
|
||||
ClientSecret string
|
||||
// Domain An IDP API domain
|
||||
Domain string
|
||||
// Audience An Audience for to authorization validation
|
||||
Audience string
|
||||
}
|
||||
|
||||
func GetDeviceAuthorizationFlowInfo(ctx context.Context, config *Config) (DeviceAuthorizationFlow, error) {
|
||||
// validate our peer's Wireguard PRIVATE key
|
||||
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
|
||||
if err != nil {
|
||||
log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error())
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
}
|
||||
|
||||
var mgmTlsEnabled bool
|
||||
if config.ManagementURL.Scheme == "https" {
|
||||
mgmTlsEnabled = true
|
||||
}
|
||||
|
||||
log.Debugf("connecting to Management Service %s", config.ManagementURL.String())
|
||||
mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled)
|
||||
if err != nil {
|
||||
log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err)
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
}
|
||||
log.Debugf("connected to management Service %s", config.ManagementURL.String())
|
||||
|
||||
serverKey, err := mgmClient.GetServerPublicKey()
|
||||
if err != nil {
|
||||
log.Errorf("failed while getting Management Service public key: %v", err)
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
}
|
||||
|
||||
protoDeviceAuthorizationFlow, err := mgmClient.GetDeviceAuthorizationFlow(*serverKey)
|
||||
if err != nil {
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
||||
log.Warnf("server couldn't find device flow, contact admin: %v", err)
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
} else {
|
||||
log.Errorf("failed to retrieve device flow: %v", err)
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
}
|
||||
}
|
||||
|
||||
err = mgmClient.Close()
|
||||
if err != nil {
|
||||
log.Errorf("failed closing Management Service client: %v", err)
|
||||
return DeviceAuthorizationFlow{}, err
|
||||
}
|
||||
|
||||
return DeviceAuthorizationFlow{
|
||||
Provider: protoDeviceAuthorizationFlow.Provider.String(),
|
||||
|
||||
ProviderConfig: ProviderConfig{
|
||||
Audience: protoDeviceAuthorizationFlow.ProviderConfig.Audience,
|
||||
ClientID: protoDeviceAuthorizationFlow.ProviderConfig.ClientID,
|
||||
ClientSecret: protoDeviceAuthorizationFlow.ProviderConfig.ClientSecret,
|
||||
Domain: protoDeviceAuthorizationFlow.ProviderConfig.Domain,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -29,7 +29,12 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
}
|
||||
|
||||
state := CtxGetState(ctx)
|
||||
defer state.Set(StatusIdle)
|
||||
defer func() {
|
||||
s, err := state.Status()
|
||||
if err != nil || s != StatusNeedsLogin {
|
||||
state.Set(StatusIdle)
|
||||
}
|
||||
}()
|
||||
|
||||
wrapErr := state.Wrap
|
||||
operation := func() error {
|
||||
@@ -57,6 +62,10 @@ func RunClient(ctx context.Context, config *Config) error {
|
||||
mgmClient, loginResp, err := connectToManagement(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied {
|
||||
state.Set(StatusNeedsLogin)
|
||||
return nil
|
||||
}
|
||||
return wrapErr(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/netbirdio/netbird/client/system"
|
||||
mgm "github.com/netbirdio/netbird/management/client"
|
||||
@@ -77,14 +76,14 @@ func loginPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey str
|
||||
func registerPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string, jwtToken string) (*mgmProto.LoginResponse, error) {
|
||||
validSetupKey, err := uuid.Parse(setupKey)
|
||||
if err != nil && jwtToken == "" {
|
||||
return nil, err
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid setup-key or no sso information provided, err: %v", err)
|
||||
}
|
||||
|
||||
log.Debugf("sending peer registration request to Management Service")
|
||||
info := system.GetInfo()
|
||||
loginResp, err := client.Register(serverPublicKey, validSetupKey.String(), jwtToken, info)
|
||||
if err != nil {
|
||||
log.Errorf("failed registering peer %v", err)
|
||||
log.Errorf("failed registering peer %v,%s", err, validSetupKey.String())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package oauth
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -11,19 +11,50 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// auth0GrantType grant type for device flow on Auth0
|
||||
// OAuthClient is a OAuth client interface for various idp providers
|
||||
type OAuthClient interface {
|
||||
RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error)
|
||||
RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error)
|
||||
WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error)
|
||||
}
|
||||
|
||||
// HTTPClient http client interface for API calls
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// DeviceAuthInfo holds information for the OAuth device login flow
|
||||
type DeviceAuthInfo 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// HostedGrantType grant type for device flow on Hosted
|
||||
const (
|
||||
auth0GrantType = "urn:ietf:params:oauth:grant-type:device_code"
|
||||
auth0RefreshGrant = "refresh_token"
|
||||
HostedGrantType = "urn:ietf:params:oauth:grant-type:device_code"
|
||||
HostedRefreshGrant = "refresh_token"
|
||||
)
|
||||
|
||||
// Auth0 client
|
||||
type Auth0 struct {
|
||||
// Auth0 API Audience for validation
|
||||
// Hosted client
|
||||
type Hosted struct {
|
||||
// Hosted API Audience for validation
|
||||
Audience string
|
||||
// Auth0 Native application client id
|
||||
// Hosted Native application client id
|
||||
ClientID string
|
||||
// Auth0 domain
|
||||
// Hosted domain
|
||||
Domain string
|
||||
|
||||
HTTPClient HTTPClient
|
||||
@@ -43,7 +74,7 @@ type TokenRequestPayload struct {
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
// TokenRequestResponse used for parsing Auth0 token's response
|
||||
// TokenRequestResponse used for parsing Hosted token's response
|
||||
type TokenRequestResponse struct {
|
||||
Error string `json:"error"`
|
||||
ErrorDescription string `json:"error_description"`
|
||||
@@ -55,8 +86,8 @@ type Claims struct {
|
||||
Audience string `json:"aud"`
|
||||
}
|
||||
|
||||
// NewAuth0DeviceFlow returns an Auth0 OAuth client
|
||||
func NewAuth0DeviceFlow(audience string, clientID string, domain string) *Auth0 {
|
||||
// NewHostedDeviceFlow returns an Hosted OAuth client
|
||||
func NewHostedDeviceFlow(audience string, clientID string, domain string) *Hosted {
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
|
||||
@@ -65,7 +96,7 @@ func NewAuth0DeviceFlow(audience string, clientID string, domain string) *Auth0
|
||||
Transport: httpTransport,
|
||||
}
|
||||
|
||||
return &Auth0{
|
||||
return &Hosted{
|
||||
Audience: audience,
|
||||
ClientID: clientID,
|
||||
Domain: domain,
|
||||
@@ -73,12 +104,12 @@ func NewAuth0DeviceFlow(audience string, clientID string, domain string) *Auth0
|
||||
}
|
||||
}
|
||||
|
||||
// RequestDeviceCode requests a device code login flow information from Auth0
|
||||
func (a *Auth0) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
||||
url := "https://" + a.Domain + "/oauth/device/code"
|
||||
// RequestDeviceCode requests a device code login flow information from Hosted
|
||||
func (h *Hosted) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
||||
url := "https://" + h.Domain + "/oauth/device/code"
|
||||
codePayload := RequestDeviceCodePayload{
|
||||
Audience: a.Audience,
|
||||
ClientID: a.ClientID,
|
||||
Audience: h.Audience,
|
||||
ClientID: h.ClientID,
|
||||
}
|
||||
p, err := json.Marshal(codePayload)
|
||||
if err != nil {
|
||||
@@ -92,7 +123,7 @@ func (a *Auth0) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
||||
|
||||
req.Header.Add("content-type", "application/json")
|
||||
|
||||
res, err := a.HTTPClient.Do(req)
|
||||
res, err := h.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return DeviceAuthInfo{}, fmt.Errorf("doing request failed with error: %v", err)
|
||||
}
|
||||
@@ -117,22 +148,22 @@ func (a *Auth0) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
||||
}
|
||||
|
||||
// WaitToken waits user's login and authorize the app. Once the user's authorize
|
||||
// it retrieves the access token from Auth0's endpoint and validates it before returning
|
||||
func (a *Auth0) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error) {
|
||||
// it retrieves the access token from Hosted's endpoint and validates it before returning
|
||||
func (h *Hosted) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error) {
|
||||
ticker := time.NewTicker(time.Duration(info.Interval) * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return TokenInfo{}, ctx.Err()
|
||||
case <-ticker.C:
|
||||
url := "https://" + a.Domain + "/oauth/token"
|
||||
url := "https://" + h.Domain + "/oauth/token"
|
||||
tokenReqPayload := TokenRequestPayload{
|
||||
GrantType: auth0GrantType,
|
||||
GrantType: HostedGrantType,
|
||||
DeviceCode: info.DeviceCode,
|
||||
ClientID: a.ClientID,
|
||||
ClientID: h.ClientID,
|
||||
}
|
||||
|
||||
body, statusCode, err := requestToken(a.HTTPClient, url, tokenReqPayload)
|
||||
body, statusCode, err := requestToken(h.HTTPClient, url, tokenReqPayload)
|
||||
if err != nil {
|
||||
return TokenInfo{}, fmt.Errorf("wait for token: %v", err)
|
||||
}
|
||||
@@ -154,7 +185,7 @@ func (a *Auth0) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo,
|
||||
return TokenInfo{}, fmt.Errorf(tokenResponse.ErrorDescription)
|
||||
}
|
||||
|
||||
err = isValidAccessToken(tokenResponse.AccessToken, a.Audience)
|
||||
err = isValidAccessToken(tokenResponse.AccessToken, h.Audience)
|
||||
if err != nil {
|
||||
return TokenInfo{}, fmt.Errorf("validate access token failed with error: %v", err)
|
||||
}
|
||||
@@ -172,15 +203,15 @@ func (a *Auth0) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo,
|
||||
}
|
||||
|
||||
// RotateAccessToken requests a new token using an existing refresh token
|
||||
func (a *Auth0) RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error) {
|
||||
url := "https://" + a.Domain + "/oauth/token"
|
||||
func (h *Hosted) RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error) {
|
||||
url := "https://" + h.Domain + "/oauth/token"
|
||||
tokenReqPayload := TokenRequestPayload{
|
||||
GrantType: auth0RefreshGrant,
|
||||
ClientID: a.ClientID,
|
||||
GrantType: HostedRefreshGrant,
|
||||
ClientID: h.ClientID,
|
||||
RefreshToken: refreshToken,
|
||||
}
|
||||
|
||||
body, statusCode, err := requestToken(a.HTTPClient, url, tokenReqPayload)
|
||||
body, statusCode, err := requestToken(h.HTTPClient, url, tokenReqPayload)
|
||||
if err != nil {
|
||||
return TokenInfo{}, fmt.Errorf("rotate access token: %v", err)
|
||||
}
|
||||
@@ -195,7 +226,7 @@ func (a *Auth0) RotateAccessToken(ctx context.Context, refreshToken string) (Tok
|
||||
return TokenInfo{}, fmt.Errorf("parsing token response failed with error: %v", err)
|
||||
}
|
||||
|
||||
err = isValidAccessToken(tokenResponse.AccessToken, a.Audience)
|
||||
err = isValidAccessToken(tokenResponse.AccessToken, h.Audience)
|
||||
if err != nil {
|
||||
return TokenInfo{}, fmt.Errorf("validate access token failed with error: %v", err)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPClient http client interface for API calls
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// DeviceAuthInfo holds information for the OAuth device login flow
|
||||
type DeviceAuthInfo 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Client is a OAuth client interface for various idp providers
|
||||
type Client interface {
|
||||
RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error)
|
||||
RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error)
|
||||
WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error)
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/99designs/keyring"
|
||||
)
|
||||
|
||||
// ServiceName default service name for saving the secret
|
||||
const ServiceName = "Wiretrustee"
|
||||
|
||||
func newSecretAPI() (keyring.Keyring, error) {
|
||||
return keyring.Open(keyring.Config{
|
||||
ServiceName: ServiceName,
|
||||
//KeychainName: ServiceName,
|
||||
})
|
||||
}
|
||||
|
||||
// SetSecret stores the secret in the system's available backend
|
||||
func SetSecret(key string, value string) error {
|
||||
storeAPI, err := newSecretAPI()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create secret API for setting a secret, error: %v", err)
|
||||
}
|
||||
|
||||
item := keyring.Item{
|
||||
Key: key,
|
||||
Data: []byte(value),
|
||||
}
|
||||
|
||||
err = storeAPI.Set(item)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set the secret, error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSecret retrieves a secret from the system's available backend
|
||||
func GetSecret(key string) (string, error) {
|
||||
storeAPI, err := newSecretAPI()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create secret API for getting a secret, error: %v", err)
|
||||
}
|
||||
|
||||
item, err := storeAPI.Get(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get secret, error: %v", err)
|
||||
}
|
||||
|
||||
return string(item.Data), nil
|
||||
}
|
||||
|
||||
// DeleteSecret deletes a secret from the system's available backend
|
||||
func DeleteSecret(key string) error {
|
||||
storeAPI, err := newSecretAPI()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create secret API for deleting a secret, error: %v", err)
|
||||
}
|
||||
|
||||
err = storeAPI.Remove(key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete secret, error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSecret(t *testing.T) {
|
||||
// this test is not ready to run as part of our ci/cd
|
||||
// todo fix testing
|
||||
if os.Getenv("CI") == "true" {
|
||||
t.Skip("skipping testing in github actions")
|
||||
}
|
||||
|
||||
key := "testing"
|
||||
value := "1234"
|
||||
err := SetSecret(key, value)
|
||||
require.NoError(t, err, "should set secret")
|
||||
|
||||
v, err := GetSecret(key)
|
||||
require.NoError(t, err, "should retrieve secret")
|
||||
require.Equal(t, value, v, "values should match")
|
||||
|
||||
err = DeleteSecret(key)
|
||||
require.NoError(t, err, "should delete secret")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package oauth
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -43,7 +43,7 @@ func (c *mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
|
||||
}, c.err
|
||||
}
|
||||
|
||||
func TestAuth0_RequestDeviceCode(t *testing.T) {
|
||||
func TestHosted_RequestDeviceCode(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
inputResBody string
|
||||
@@ -107,14 +107,14 @@ func TestAuth0_RequestDeviceCode(t *testing.T) {
|
||||
err: testCase.inputReqError,
|
||||
}
|
||||
|
||||
auth0 := Auth0{
|
||||
hosted := Hosted{
|
||||
Audience: testCase.expectPayload.Audience,
|
||||
ClientID: testCase.expectPayload.ClientID,
|
||||
Domain: "test.auth0.com",
|
||||
Domain: "test.hosted.com",
|
||||
HTTPClient: &httpClient,
|
||||
}
|
||||
|
||||
authInfo, err := auth0.RequestDeviceCode(context.TODO())
|
||||
authInfo, err := hosted.RequestDeviceCode(context.TODO())
|
||||
testCase.testingErrFunc(t, err, testCase.expectedErrorMSG)
|
||||
|
||||
payload, _ := json.Marshal(testCase.expectPayload)
|
||||
@@ -127,7 +127,7 @@ func TestAuth0_RequestDeviceCode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth0_WaitToken(t *testing.T) {
|
||||
func TestHosted_WaitToken(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
inputResBody string
|
||||
@@ -153,7 +153,7 @@ func TestAuth0_WaitToken(t *testing.T) {
|
||||
}
|
||||
|
||||
tokenReqPayload := TokenRequestPayload{
|
||||
GrantType: auth0GrantType,
|
||||
GrantType: HostedGrantType,
|
||||
DeviceCode: defaultInfo.DeviceCode,
|
||||
ClientID: "test",
|
||||
}
|
||||
@@ -267,16 +267,16 @@ func TestAuth0_WaitToken(t *testing.T) {
|
||||
countResBody: testCase.inputCountResBody,
|
||||
}
|
||||
|
||||
auth0 := Auth0{
|
||||
hosted := Hosted{
|
||||
Audience: testCase.inputAudience,
|
||||
ClientID: testCase.expectPayload.ClientID,
|
||||
Domain: "test.auth0.com",
|
||||
Domain: "test.hosted.com",
|
||||
HTTPClient: &httpClient,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), testCase.inputTimeout)
|
||||
defer cancel()
|
||||
tokenInfo, err := auth0.WaitToken(ctx, testCase.inputInfo)
|
||||
tokenInfo, err := hosted.WaitToken(ctx, testCase.inputInfo)
|
||||
testCase.testingErrFunc(t, err, testCase.expectedErrorMSG)
|
||||
|
||||
var payload []byte
|
||||
@@ -294,7 +294,7 @@ func TestAuth0_WaitToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth0_RotateAccessToken(t *testing.T) {
|
||||
func TestHosted_RotateAccessToken(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
inputResBody string
|
||||
@@ -318,7 +318,7 @@ func TestAuth0_RotateAccessToken(t *testing.T) {
|
||||
}
|
||||
|
||||
tokenReqPayload := TokenRequestPayload{
|
||||
GrantType: auth0RefreshGrant,
|
||||
GrantType: HostedRefreshGrant,
|
||||
ClientID: "test",
|
||||
RefreshToken: "refresh_test",
|
||||
}
|
||||
@@ -391,14 +391,14 @@ func TestAuth0_RotateAccessToken(t *testing.T) {
|
||||
MaxReqs: testCase.inputMaxReqs,
|
||||
}
|
||||
|
||||
auth0 := Auth0{
|
||||
hosted := Hosted{
|
||||
Audience: testCase.inputAudience,
|
||||
ClientID: testCase.expectPayload.ClientID,
|
||||
Domain: "test.auth0.com",
|
||||
Domain: "test.hosted.com",
|
||||
HTTPClient: &httpClient,
|
||||
}
|
||||
|
||||
tokenInfo, err := auth0.RotateAccessToken(context.TODO(), testCase.expectPayload.RefreshToken)
|
||||
tokenInfo, err := hosted.RotateAccessToken(context.TODO(), testCase.expectPayload.RefreshToken)
|
||||
testCase.testingErrFunc(t, err, testCase.expectedErrorMSG)
|
||||
|
||||
var payload []byte
|
||||
@@ -10,8 +10,10 @@ type StatusType string
|
||||
const (
|
||||
StatusIdle StatusType = "Idle"
|
||||
|
||||
StatusConnecting StatusType = "Connecting"
|
||||
StatusConnected StatusType = "Connected"
|
||||
StatusConnecting StatusType = "Connecting"
|
||||
StatusConnected StatusType = "Connected"
|
||||
StatusNeedsLogin StatusType = "NeedsLogin"
|
||||
StatusLoginFailed StatusType = "LoginFailed"
|
||||
)
|
||||
|
||||
// CtxInitState setup context state into the context tree.
|
||||
|
||||
Reference in New Issue
Block a user