diff --git a/pkg/cmd/util/tokencmd/request_token.go b/pkg/cmd/util/tokencmd/request_token.go index a725893c4d60..b75292f197b5 100644 --- a/pkg/cmd/util/tokencmd/request_token.go +++ b/pkg/cmd/util/tokencmd/request_token.go @@ -30,7 +30,7 @@ const ( // See IETF Draft: // https://tools.ietf.org/html/draft-ietf-oauth-discovery-04#section-2 // Copied from pkg/cmd/server/origin/nonapiserver.go - oauthMetadataEndpoint = "/.well-known/oauth-authorization-server" + OauthMetadataEndpoint = "/.well-known/oauth-authorization-server" // openShiftCLIClientID is the name of the CLI OAuth client, copied from pkg/oauth/apiserver/auth.go openShiftCLIClientID = "openshift-challenging-client" @@ -108,7 +108,7 @@ func (o *RequestTokenOptions) SetDefaultOsinConfig() error { if err != nil { return err } - resp, err := request(rt, strings.TrimRight(o.ClientConfig.Host, "/")+oauthMetadataEndpoint, nil) + resp, err := request(rt, strings.TrimRight(o.ClientConfig.Host, "/")+OauthMetadataEndpoint, nil) if err != nil { return err } diff --git a/pkg/cmd/util/tokencmd/request_token_test.go b/pkg/cmd/util/tokencmd/request_token_test.go index c5aea96f1ec4..f9357e06cd09 100644 --- a/pkg/cmd/util/tokencmd/request_token_test.go +++ b/pkg/cmd/util/tokencmd/request_token_test.go @@ -631,7 +631,7 @@ func TestSetDefaultOsinConfig(t *testing.T) { t.Errorf("%s: Expected GET, got %s", tc.name, req.Method) return } - if req.URL.Path != oauthMetadataEndpoint { + if req.URL.Path != OauthMetadataEndpoint { t.Errorf("%s: Expected metadata endpoint, got %s", tc.name, req.URL.Path) return } diff --git a/pkg/oc/cli/cmd/login/loginoptions_test.go b/pkg/oc/cli/cmd/login/loginoptions_test.go index 1aace2eb283f..2a7217d2c9be 100644 --- a/pkg/oc/cli/cmd/login/loginoptions_test.go +++ b/pkg/oc/cli/cmd/login/loginoptions_test.go @@ -2,19 +2,29 @@ package login import ( "crypto/tls" + "encoding/json" "fmt" + "io" + "io/ioutil" "net/http" "net/http/httptest" + "reflect" "regexp" "strings" "testing" + "github.com/spf13/pflag" + "github.com/MakeNowJust/heredoc" "github.com/openshift/origin/pkg/cmd/util/clientcmd" + "github.com/openshift/origin/pkg/cmd/util/tokencmd" + "github.com/openshift/origin/pkg/oauth/util" "github.com/openshift/origin/pkg/oc/cli/config" + kapierrs "k8s.io/apimachinery/pkg/api/errors" restclient "k8s.io/client-go/rest" + kclientcmd "k8s.io/client-go/tools/clientcmd" kclientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) @@ -256,6 +266,109 @@ func TestDialToHTTPServer(t *testing.T) { } } +type oauthMetadataResponse struct { + metadata *util.OauthAuthorizationServerMetadata +} + +func (r *oauthMetadataResponse) Serialize() string { + b, err := json.Marshal(r.metadata) + if err != nil { + return "" + } + + return string(b) +} + +func TestPreserveErrTypeAuthInfo(t *testing.T) { + invoked := make(chan struct{}, 2) + metadataResponse := &oauthMetadataResponse{} + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + invoked <- struct{}{} + + if r.URL.Path == tokencmd.OauthMetadataEndpoint { + w.WriteHeader(http.StatusOK) + io.WriteString(w, metadataResponse.Serialize()) + return + } + w.WriteHeader(http.StatusUnauthorized) + })) + + metadataResponse.metadata = &util.OauthAuthorizationServerMetadata{ + Issuer: server.URL, + AuthorizationEndpoint: server.URL + "/oauth/authorize", + TokenEndpoint: server.URL + "/oauth/token", + CodeChallengeMethodsSupported: []string{"plain", "S256"}, + } + defer server.Close() + + testCases := map[string]struct { + serverURL string + evalExpectedErr func(error) bool + }{ + "preserve unauthorized server errors": { + serverURL: server.URL, + }, + } + + for name, test := range testCases { + t.Logf("evaluating test: %s", name) + + clientConfig := &restclient.Config{ + Host: test.serverURL, + } + + options := newLoginOptions(test.serverURL, "test", "test", false) + options.Config = clientConfig + + err := options.gatherAuthInfo() + if err == nil { + t.Fatalf("expecting unauthorized error when gathering authinfo") + } + + if !kapierrs.IsUnauthorized(err) { + t.Fatalf("expecting error of type metav1.StatusReasonUnauthorized, but got %v", reflect.TypeOf(err)) + } + } +} + +func newLoginOptions(server string, username string, password string, insecure bool) *LoginOptions { + flagset := pflag.NewFlagSet("test-flags", pflag.ContinueOnError) + flags := []string{} + clientConfig := defaultClientConfig(flagset) + flagset.Parse(flags) + + startingConfig, _ := clientConfig.RawConfig() + + loginOptions := &LoginOptions{ + Server: server, + StartingKubeConfig: &startingConfig, + Username: username, + Password: password, + InsecureTLS: insecure, + + Out: ioutil.Discard, + ErrOut: ioutil.Discard, + } + + return loginOptions +} + +func defaultClientConfig(flags *pflag.FlagSet) kclientcmd.ClientConfig { + loadingRules := &kclientcmd.ClientConfigLoadingRules{ExplicitPath: ""} + + flags.StringVar(&loadingRules.ExplicitPath, config.OpenShiftConfigFlagName, "", "Path to the config file to use for CLI requests.") + + overrides := &kclientcmd.ConfigOverrides{} + overrideFlags := kclientcmd.RecommendedConfigOverrideFlags("") + overrideFlags.ContextOverrideFlags.Namespace.ShortName = "n" + kclientcmd.BindOverrideFlags(overrides, flags, overrideFlags) + + clientConfig := kclientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) + + return clientConfig +} + func TestDialToHTTPSServer(t *testing.T) { invoked := make(chan struct{}, 1) server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {