diff --git a/oauthproxy.go b/oauthproxy.go index 5ddd46bfbf..c8e5d9a927 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -69,9 +69,11 @@ type OAuthProxy struct { appDirector redirect.AppDirector passAuthorization bool + passAccessToken bool encodeState bool - client wrapper.HttpClient + client wrapper.HttpClient + validateClient wrapper.HttpClient } // NewOAuthProxy creates a new instance of OAuthProxy from the options provided @@ -103,11 +105,19 @@ func NewOAuthProxy(opts *options.Options) (*OAuthProxy, error) { return nil, err } + var validateServiceClient wrapper.HttpClient + if opts.ValidateService.ServiceName != "" { + validateServiceClient, err = opts.ValidateService.NewService() + if err != nil { + return nil, err + } + } + preAuthChain, err := buildPreAuthChain(opts) if err != nil { return nil, fmt.Errorf("could not build pre-auth chain: %v", err) } - sessionChain := buildSessionChain(opts, provider, sessionStore, serviceClient) + sessionChain := buildSessionChain(opts, provider, sessionStore, serviceClient, validateServiceClient) redirectValidator := redirect.NewValidator(opts.WhitelistDomains) appDirector := redirect.NewAppDirector(redirect.AppDirectorOpts{ @@ -137,8 +147,10 @@ func NewOAuthProxy(opts *options.Options) (*OAuthProxy, error) { appDirector: appDirector, encodeState: opts.EncodeState, passAuthorization: opts.PassAuthorization, + passAccessToken: opts.PassAccessToken, - client: serviceClient, + client: serviceClient, + validateClient: validateServiceClient, } p.buildServeMux(opts.ProxyPrefix) @@ -146,7 +158,7 @@ func NewOAuthProxy(opts *options.Options) (*OAuthProxy, error) { } func SetLogger(log wrapper.Log) { - util.Logger = &log + util.Logger = log } func (p *OAuthProxy) buildServeMux(proxyPrefix string) { @@ -183,16 +195,18 @@ func buildPreAuthChain(opts *options.Options) (alice.Chain, error) { return chain, nil } -func buildSessionChain(opts *options.Options, provider providers.Provider, sessionStore sessionsapi.SessionStore, serviceClient wrapper.HttpClient) alice.Chain { +func buildSessionChain(opts *options.Options, provider providers.Provider, sessionStore sessionsapi.SessionStore, serviceClient wrapper.HttpClient, validateClient wrapper.HttpClient) alice.Chain { chain := alice.New() ss, loadSession := middleware.NewStoredSessionLoader(&middleware.StoredSessionLoaderOptions{ - SessionStore: sessionStore, - RefreshPeriod: opts.Cookie.Refresh, - RefreshSession: provider.RefreshSession, - ValidateSession: provider.ValidateSession, - RefreshClient: serviceClient, - RefreshRequestTimeout: provider.Data().RedeemTimeout, + SessionStore: sessionStore, + RefreshPeriod: opts.Cookie.Refresh, + RefreshSession: provider.RefreshSession, + ValidateSession: provider.ValidateSession, + RefreshClient: serviceClient, + ValidateClient: validateClient, + RefreshRequestTimeout: provider.Data().RedeemTimeout, + ValidateRequestTimeout: provider.Data().RedeemTimeout, }) chain = chain.Append(loadSession) provider.Data().StoredSession = ss @@ -381,30 +395,35 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { csrf.SetSessionNonce(session) updateKeysCallback := func(args ...interface{}) { - if !p.provider.ValidateSession(req.Context(), session) { - util.SendError(fmt.Sprintf("Session validation failed: %s", session), rw, http.StatusForbidden) - return - } - util.Logger.Debug("Session validated successfully") - if !p.redirectValidator.IsValidRedirect(appRedirect) { - appRedirect = "/" - util.Logger.Debugf("Invalid redirect, defaulting to root: %s", appRedirect) - } - // set cookie, or deny - authorized, err := p.provider.Authorize(req.Context(), session) - if err != nil { - util.Logger.Errorf("Error with authorization: %v", err) - } - if p.validator(session.Email) && authorized { - util.Logger.Infof("Authenticated successfully via OAuth2: %s", session) - err := p.SaveSession(rw, req, session) + validateSessionCallback := func(args ...interface{}) { + util.Logger.Debug("Session validated successfully") + if !p.redirectValidator.IsValidRedirect(appRedirect) { + appRedirect = "/" + util.Logger.Debugf("Invalid redirect, defaulting to root: %s", appRedirect) + } + // set cookie, or deny + authorized, err := p.provider.Authorize(req.Context(), session) if err != nil { - util.SendError(fmt.Sprintf("Error saving session state: %v", err), rw, http.StatusInternalServerError) - return + util.Logger.Errorf("Error with authorization: %v", err) + } + if p.validator(session.Email) && authorized { + util.Logger.Infof("Authenticated successfully via OAuth2: %s", session) + err := p.SaveSession(rw, req, session) + if err != nil { + util.SendError(fmt.Sprintf("Error saving session state: %v", err), rw, http.StatusInternalServerError) + return + } + redirectToLocation(rw, appRedirect) + } else { + util.SendError("Invalid authentication via OAuth2: unauthorized", rw, http.StatusForbidden) } - redirectToLocation(rw, appRedirect) - } else { - util.SendError("Invalid authentication via OAuth2: unauthorized", rw, http.StatusForbidden) + } + valid, isAsync := p.provider.ValidateSession(req.Context(), session, p.validateClient, validateSessionCallback, p.provider.Data().RedeemTimeout) + if !valid { + util.SendError(fmt.Sprintf("Session validation failed: %s", session), rw, http.StatusForbidden) + return + } else if !isAsync { + validateSessionCallback() } } if p.provider.Data().NeedsVerifier { @@ -441,6 +460,10 @@ func (p *OAuthProxy) Proxy(rw http.ResponseWriter, req *http.Request) { proxywasm.AddHttpRequestHeader("Authorization", fmt.Sprintf("%s %s", providers.TokenTypeBearer, session.IDToken)) util.Logger.Debug("Authorization header add id token") } + if p.passAccessToken { + proxywasm.AddHttpRequestHeader("X-Forwarded-Access-Token", session.AccessToken) + util.Logger.Debug("X-Forwarded-Access-Token header add access token") + } if cookies, ok := rw.Header()[SetCookieHeader]; ok && len(cookies) > 0 { newCookieValue := strings.Join(cookies, ",") if p.ctx != nil { diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index a3fc729c8d..8cab15dea5 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -22,16 +22,18 @@ type Options struct { WhitelistDomains []string `mapstructure:"whitelist_domains"` - Cookie Cookie `mapstructure:",squash"` - Session SessionOptions `mapstructure:",squash"` - Service Service `mapstructure:",squash"` - MatchRules MatchRules `mapstructure:",squash"` + Cookie Cookie `mapstructure:",squash"` + Session SessionOptions `mapstructure:",squash"` + Service Service `mapstructure:",squash"` + ValidateService ValidateService `mapstructure:",squash"` + MatchRules MatchRules `mapstructure:",squash"` Providers Providers SkipAuthPreflight bool `mapstructure:"skip_auth_preflight"` EncodeState bool `mapstructure:"encode_state"` PassAuthorization bool `mapstructure:"pass_authorization_header"` + PassAccessToken bool `mapstructure:"pass_access_token"` VerifierInterval time.Duration `mapstructure:"verifier_interval"` UpdateKeysInterval time.Duration `mapstructure:"update_keys_interval"` @@ -57,6 +59,7 @@ func NewOptions() *Options { Session: sessionOptionsDefaults(), SkipAuthPreflight: false, PassAuthorization: true, + PassAccessToken: false, VerifierInterval: 2 * time.Second, // 5 seconds UpdateKeysInterval: 24 * time.Hour, // 24 hours MatchRules: matchRulesDefaults(), diff --git a/pkg/apis/options/providers.go b/pkg/apis/options/providers.go index 2e763256e1..6d732a2dba 100644 --- a/pkg/apis/options/providers.go +++ b/pkg/apis/options/providers.go @@ -70,6 +70,8 @@ const ( OIDCProvider ProviderType = "oidc" AliyunProvider ProviderType = "aliyun" + + GitHubProvider ProviderType = "github" ) type OIDCOptions struct { diff --git a/pkg/apis/options/service.go b/pkg/apis/options/service.go index 06cc771886..2bc51c3210 100644 --- a/pkg/apis/options/service.go +++ b/pkg/apis/options/service.go @@ -25,3 +25,22 @@ func (s *Service) NewService() (wrapper.HttpClient, error) { }) return client, nil } + +type ValidateService struct { + // 带服务类型的完整 FQDN 名称,例如 keycloak.static, auth.dns + ServiceName string `mapstructure:"validate_service_name"` + ServicePort int64 `mapstructure:"validate_service_port"` + ServiceHost string `mapstructure:"validate_service_host"` +} + +func (s *ValidateService) NewService() (wrapper.HttpClient, error) { + if s.ServiceName == "" || s.ServicePort == 0 { + return nil, errors.New("invalid service config") + } + client := wrapper.NewClusterClient(&wrapper.FQDNCluster{ + FQDN: s.ServiceName, + Host: s.ServiceHost, + Port: s.ServicePort, + }) + return client, nil +} diff --git a/pkg/middleware/stored_session.go b/pkg/middleware/stored_session.go index b176c1758c..3801bc6b73 100644 --- a/pkg/middleware/stored_session.go +++ b/pkg/middleware/stored_session.go @@ -28,17 +28,23 @@ type StoredSessionLoaderOptions struct { // How often should sessions be refreshed RefreshPeriod time.Duration - // Provider based session refreshing + // Provider based session + // return value isAsync and error RefreshSession func(context.Context, *sessionsapi.SessionState, wrapper.HttpClient, func(args ...interface{}), uint32) (bool, error) // Provider based session validation. // If the session is older than `RefreshPeriod` but the provider doesn't // refresh it, we must re-validate using this validation. - ValidateSession func(context.Context, *sessionsapi.SessionState) bool + // return value valid and isAsync + ValidateSession func(context.Context, *sessionsapi.SessionState, wrapper.HttpClient, func(args ...interface{}), uint32) (bool, bool) // Refresh request parameters RefreshClient wrapper.HttpClient RefreshRequestTimeout uint32 + + // Validate request parameters + ValidateClient wrapper.HttpClient + ValidateRequestTimeout uint32 } // NewStoredSessionLoader creates a new StoredSessionLoader which loads @@ -47,12 +53,14 @@ type StoredSessionLoaderOptions struct { // If a session was loader by a previous handler, it will not be replaced. func NewStoredSessionLoader(opts *StoredSessionLoaderOptions) (*StoredSessionLoader, alice.Constructor) { ss := &StoredSessionLoader{ - store: opts.SessionStore, - refreshPeriod: opts.RefreshPeriod, - sessionRefresher: opts.RefreshSession, - sessionValidator: opts.ValidateSession, - refreshClient: opts.RefreshClient, - refreshRequestTimeout: opts.RefreshRequestTimeout, + store: opts.SessionStore, + refreshPeriod: opts.RefreshPeriod, + sessionRefresher: opts.RefreshSession, + sessionValidator: opts.ValidateSession, + refreshClient: opts.RefreshClient, + refreshRequestTimeout: opts.RefreshRequestTimeout, + validateClient: opts.ValidateClient, + validateRequestTimeout: opts.ValidateRequestTimeout, } return ss, ss.loadSession } @@ -63,13 +71,18 @@ type StoredSessionLoader struct { store sessionsapi.SessionStore refreshPeriod time.Duration sessionRefresher func(context.Context, *sessionsapi.SessionState, wrapper.HttpClient, func(args ...interface{}), uint32) (bool, error) - sessionValidator func(context.Context, *sessionsapi.SessionState) bool + sessionValidator func(context.Context, *sessionsapi.SessionState, wrapper.HttpClient, func(args ...interface{}), uint32) (bool, bool) // Refresh request parameters refreshClient wrapper.HttpClient refreshRequestTimeout uint32 - RemoteKeySet *oidc.KeySet - NeedsVerifier bool + + // Validate request parameters + validateClient wrapper.HttpClient + validateRequestTimeout uint32 + + RemoteKeySet *oidc.KeySet + NeedsVerifier bool } // loadSession attempts to load a session as identified by the request cookies. @@ -90,15 +103,27 @@ func (s *StoredSessionLoader) loadSession(next http.Handler) http.Handler { resumeFlag := args[1].(bool) updateKeysCallback := func(args ...interface{}) { resumeFlag := args[0].(bool) - if session != nil && s.validateSession(req.Context(), session) != nil { - session = nil + validateSessionCallback := func(args ...interface{}) { + resumeFlag := args[0].(bool) + sessionValid := args[1].(bool) + if !sessionValid { + session = nil + } + scope.Session = session + next.ServeHTTP(rw, req) + if resumeFlag { + if rw.Header().Get(util.ResponseCode) == string(http.StatusOK) { + proxywasm.ResumeHttpRequest() + } + } } - scope.Session = session - next.ServeHTTP(rw, req) - if resumeFlag { - if rw.Header().Get(util.ResponseCode) == string(http.StatusOK) { - proxywasm.ResumeHttpRequest() + if session != nil { + err, isAsync := s.validateSession(req.Context(), session, validateSessionCallback) + if !isAsync { + validateSessionCallback(resumeFlag, err == nil) } + } else { + validateSessionCallback(resumeFlag, true) } } keysNeedsUpdate := (session != nil) && (s.NeedsVerifier) @@ -206,14 +231,14 @@ func (s *StoredSessionLoader) refreshSession(rw http.ResponseWriter, req *http.R // validateSession checks whether the session has expired and performs // provider validation on the session. // An error implies the session is no longer valid. -func (s *StoredSessionLoader) validateSession(ctx context.Context, session *sessionsapi.SessionState) error { +func (s *StoredSessionLoader) validateSession(ctx context.Context, session *sessionsapi.SessionState, callback func(args ...interface{})) (error, bool) { if session.IsExpired() { - return errors.New("session is expired") + return errors.New("session is expired"), false } - - if !s.sessionValidator(ctx, session) { - return errors.New("session is invalid") + valid, isAsync := s.sessionValidator(ctx, session, s.validateClient, callback, s.validateRequestTimeout) + if !valid { + return errors.New("session is invalid"), isAsync } - return nil + return nil, isAsync } diff --git a/pkg/util/logger.go b/pkg/util/logger.go index e88d1634a9..d8edf9bd44 100644 --- a/pkg/util/logger.go +++ b/pkg/util/logger.go @@ -7,7 +7,7 @@ import ( "github.com/higress-group/proxy-wasm-go-sdk/proxywasm" ) -var Logger *wrapper.Log +var Logger wrapper.Log func SendError(errMsg string, rw http.ResponseWriter, status int) { Logger.Errorf(errMsg) diff --git a/providers/github.go b/providers/github.go new file mode 100644 index 0000000000..c7da498f3a --- /dev/null +++ b/providers/github.go @@ -0,0 +1,80 @@ +package providers + +import ( + "context" + "net/http" + "net/url" + + "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" + "github.com/higress-group/oauth2-proxy/pkg/apis/sessions" +) + +// GitHubProvider represents an GitHub based Identity Provider +type GitHubProvider struct { + *ProviderData +} + +var _ Provider = (*GitHubProvider)(nil) + +const ( + githubProviderName = "GitHub" + githubDefaultScope = "user:email read:org" + orgTeamSeparator = ":" +) + +var ( + // Default Login URL for GitHub. + // Pre-parsed URL of https://github.org/login/oauth/authorize. + githubDefaultLoginURL = &url.URL{ + Scheme: "https", + Host: "github.com", + Path: "/login/oauth/authorize", + } + + // Default Redeem URL for GitHub. + // Pre-parsed URL of https://github.org/login/oauth/access_token. + githubDefaultRedeemURL = &url.URL{ + Scheme: "https", + Host: "github.com", + Path: "/login/oauth/access_token", + } + + // Default Validation URL for GitHub. + // ValidationURL is the API Base URL. + // Other API requests are based off of this (eg to fetch users/groups). + // Pre-parsed URL of https://api.github.com/. + githubDefaultValidateURL = &url.URL{ + Scheme: "https", + Host: "api.github.com", + Path: "/", + } +) + +// NewGitHubProvider initiates a new GitHubProvider +func NewGitHubProvider(p *ProviderData) *GitHubProvider { + p.setProviderDefaults(providerDefaults{ + name: githubProviderName, + loginURL: githubDefaultLoginURL, + redeemURL: githubDefaultRedeemURL, + profileURL: nil, + validateURL: githubDefaultValidateURL, + scope: githubDefaultScope, + }) + + provider := &GitHubProvider{ProviderData: p} + return provider +} + +func makeGitHubHeader(accessToken string) http.Header { + // extra headers required by the GitHub API when making authenticated requests + extraHeaders := map[string]string{ + acceptHeader: "application/vnd.github.v3+json", + "User-Agent": "HigressOidcPlugin/1.0", + } + return makeAuthorizationHeader(TokenTypeToken, accessToken, extraHeaders) +} + +// ValidateSession validates the AccessToken +func (p *GitHubProvider) ValidateSession(ctx context.Context, s *sessions.SessionState, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, bool) { + return validateToken(ctx, p, s.AccessToken, makeGitHubHeader(s.AccessToken), client, callback, timeout) +} diff --git a/providers/internal_util.go b/providers/internal_util.go new file mode 100644 index 0000000000..93c49d5f56 --- /dev/null +++ b/providers/internal_util.go @@ -0,0 +1,89 @@ +package providers + +import ( + "context" + "net/http" + "net/url" + + "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" + "github.com/higress-group/oauth2-proxy/pkg/util" +) + +// stripToken is a helper function to obfuscate "access_token" +// query parameters +func stripToken(endpoint string) string { + return stripParam("access_token", endpoint) +} + +// stripParam generalizes the obfuscation of a particular +// query parameter - typically 'access_token' or 'client_secret' +// The parameter's second half is replaced by '...' and returned +// as part of the encoded query parameters. +// If the target parameter isn't found, the endpoint is returned +// unmodified. +func stripParam(param, endpoint string) string { + u, err := url.Parse(endpoint) + if err != nil { + util.Logger.Errorf("error attempting to strip %s: %s", param, err) + return endpoint + } + + if u.RawQuery != "" { + values, err := url.ParseQuery(u.RawQuery) + if err != nil { + util.Logger.Errorf("error attempting to strip %s: %s", param, err) + return u.String() + } + + if val := values.Get(param); val != "" { + values.Set(param, val[:(len(val)/2)]+"...") + u.RawQuery = values.Encode() + return u.String() + } + } + + return endpoint +} + +// validateToken returns true if token is valid +func validateToken(ctx context.Context, p Provider, accessToken string, header http.Header, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, bool) { + if accessToken == "" || p.Data().ValidateURL == nil || p.Data().ValidateURL.String() == "" { + return false, false + } + endpoint := p.Data().ValidateURL.String() + if len(header) == 0 { + params := url.Values{"access_token": {accessToken}} + if hasQueryParams(endpoint) { + endpoint = endpoint + "&" + params.Encode() + } else { + endpoint = endpoint + "?" + params.Encode() + } + } + var headerArray [][2]string + for key, values := range header { + for _, value := range values { + headerArray = append(headerArray, [2]string{key, value}) + } + } + + client.Get(endpoint, headerArray, func(statusCode int, responseHeaders http.Header, responseBody []byte) { + util.Logger.Debugf("%d GET %s %s", statusCode, stripToken(endpoint), responseBody) + if statusCode == 200 { + callback(true, true) + } else { + util.Logger.Errorf("token validation request failed: status %d - %s", statusCode, responseBody) + callback(false, false) + } + }, timeout) + return true, true +} + +// hasQueryParams check if URL has query parameters +func hasQueryParams(endpoint string) bool { + endpointURL, err := url.Parse(endpoint) + if err != nil { + return false + } + + return len(endpointURL.RawQuery) != 0 +} diff --git a/providers/oidc.go b/providers/oidc.go index 7b7ba8a968..7c7056caf3 100644 --- a/providers/oidc.go +++ b/providers/oidc.go @@ -117,21 +117,21 @@ func (p *OIDCProvider) EnrichSession(_ context.Context, s *sessions.SessionState } // ValidateSession checks that the session's IDToken is still valid -func (p *OIDCProvider) ValidateSession(ctx context.Context, s *sessions.SessionState) bool { +func (p *OIDCProvider) ValidateSession(ctx context.Context, s *sessions.SessionState, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, bool) { _, err := p.Verifier.Verify(ctx, s.IDToken) if err != nil { util.Logger.Errorf("id_token verification failed: %v", err) - return false + return false, false } if p.SkipNonce { - return true + return true, false } err = p.checkNonce(s) if err != nil { util.Logger.Errorf("nonce verification failed: %v", err) - return false + return false, false } - return true + return true, false } // RefreshSession uses the RefreshToken to fetch new Access and ID Tokens diff --git a/providers/provider_default.go b/providers/provider_default.go index ee43b31365..73d04a0661 100644 --- a/providers/provider_default.go +++ b/providers/provider_default.go @@ -2,7 +2,9 @@ package providers import ( "context" + "encoding/json" "errors" + "fmt" "io" "net/http" "net/url" @@ -75,13 +77,35 @@ func (p *ProviderData) Redeem(ctx context.Context, redirectURL, code, codeVerifi req.Body.Close() client.Post(p.RedeemURL.String(), headerArray, bodyBytes, func(statusCode int, responseHeaders http.Header, responseBody []byte) { - token, err := util.UnmarshalToken(responseHeaders, responseBody) - if err != nil { - util.SendError(err.Error(), nil, http.StatusInternalServerError) - return - } - session := &sessions.SessionState{ - AccessToken: token.AccessToken, + // blindly try json and x-www-form-urlencoded + var ( + jsonResponse struct { + AccessToken string `json:"access_token"` + } + session *sessions.SessionState + ) + + jsonInValid := json.Unmarshal(responseBody, &jsonResponse) + if jsonInValid == nil && jsonResponse.AccessToken != "" { + session = &sessions.SessionState{ + AccessToken: jsonResponse.AccessToken, + } + session.CreatedAtNow() + } else { + values, err := url.ParseQuery(string(responseBody)) + if err != nil { + util.SendError(err.Error(), nil, http.StatusInternalServerError) + return + } + if token := values.Get("access_token"); token != "" { + session = &sessions.SessionState{ + AccessToken: token, + } + session.CreatedAtNow() + } else { + util.SendError(fmt.Sprintf("no access token found %s", responseBody), nil, http.StatusInternalServerError) + return + } } callback(session) }, timeout) @@ -117,8 +141,8 @@ func (p *ProviderData) Authorize(_ context.Context, s *sessions.SessionState) (b } // ValidateSession validates the AccessToken -func (p *ProviderData) ValidateSession(ctx context.Context, s *sessions.SessionState) bool { - return true +func (p *ProviderData) ValidateSession(ctx context.Context, s *sessions.SessionState, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, bool) { + return true, false } // RefreshSession refreshes the user's session diff --git a/providers/providers.go b/providers/providers.go index e413cb9b60..996d36915a 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -31,7 +31,7 @@ type Provider interface { GetEmailAddress(ctx context.Context, s *sessions.SessionState) (string, error) EnrichSession(ctx context.Context, s *sessions.SessionState) error Authorize(ctx context.Context, s *sessions.SessionState) (bool, error) - ValidateSession(ctx context.Context, s *sessions.SessionState) bool + ValidateSession(ctx context.Context, s *sessions.SessionState, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, bool) RefreshSession(ctx context.Context, s *sessions.SessionState, client wrapper.HttpClient, callback func(args ...interface{}), timeout uint32) (bool, error) } @@ -45,6 +45,8 @@ func NewProvider(providerConfig options.Provider) (Provider, error) { return NewOIDCProvider(providerData, providerConfig.OIDCConfig), nil case options.AliyunProvider: return NewAliyunProvider(providerData), nil + case options.GitHubProvider: + return NewGitHubProvider(providerData), nil default: return nil, fmt.Errorf("unknown provider type %q", providerConfig.Type) } @@ -158,7 +160,7 @@ func providerRequiresOIDCProviderVerifier(providerType options.ProviderType) (bo switch providerType { case options.OIDCProvider: return true, nil - case options.AliyunProvider: + case options.AliyunProvider, options.GitHubProvider: return false, nil default: return false, fmt.Errorf("unknown provider type: %s", providerType) diff --git a/providers/util.go b/providers/util.go index 49607c5299..6b200eaae7 100644 --- a/providers/util.go +++ b/providers/util.go @@ -10,6 +10,7 @@ import ( const ( TokenTypeBearer = "Bearer" + TokenTypeToken = "token" acceptHeader = "Accept" acceptApplicationJSON = "application/json"