Example #1
0
func TestLogin(t *testing.T) {
	clientcmd.DefaultCluster = clientcmdapi.Cluster{Server: ""}

	_, clusterAdminKubeConfig, err := testutil.StartTestMaster()

	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	username := "******"
	password := "******"
	project := "the-singularity-is-near"
	server := clusterAdminClientConfig.Host

	loginOptions := newLoginOptions(server, username, password, true)

	if err := loginOptions.GatherInfo(); err != nil {
		t.Fatalf("Error trying to determine server info: %v", err)
	}

	if loginOptions.Username != username {
		t.Fatalf("Unexpected user after authentication: %#v", loginOptions)
	}

	newProjectOptions := &newproject.NewProjectOptions{
		Client:      clusterAdminClient,
		ProjectName: project,
		AdminRole:   bootstrappolicy.AdminRoleName,
		AdminUser:   username,
	}
	if err := newProjectOptions.Run(false); err != nil {
		t.Fatalf("unexpected error, a project is required to continue: %v", err)
	}

	oClient, _ := client.New(loginOptions.Config)
	p, err := oClient.Projects().Get(project)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	if p.Name != project {
		t.Fatalf("unexpected project: %#v", p)
	}

	// TODO Commented because of incorrectly hitting cache when listing projects.
	// Should be enabled again when cache eviction is properly fixed.

	// err = loginOptions.GatherProjectInfo()
	// if err != nil {
	// 	t.Fatalf("unexpected error: %v", err)
	// }

	// if loginOptions.Project != project {
	// 	t.Fatalf("Expected project %v but got %v", project, loginOptions.Project)
	// }

	// configFile, err := ioutil.TempFile("", "openshiftconfig")
	// if err != nil {
	// 	t.Fatalf("unexpected error: %v", err)
	// }
	// defer os.Remove(configFile.Name())

	// if _, err = loginOptions.SaveConfig(configFile.Name()); err != nil {
	// 	t.Fatalf("unexpected error: %v", err)
	// }

	userWhoamiOptions := cmd.WhoAmIOptions{UserInterface: oClient.Users(), Out: ioutil.Discard}
	retrievedUser, err := userWhoamiOptions.WhoAmI()
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if retrievedUser.Name != username {
		t.Errorf("expected %v, got %v", retrievedUser.Name, username)
	}

	adminWhoamiOptions := cmd.WhoAmIOptions{UserInterface: clusterAdminClient.Users(), Out: ioutil.Discard}
	retrievedAdmin, err := adminWhoamiOptions.WhoAmI()
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if retrievedAdmin.Name != "system:admin" {
		t.Errorf("expected %v, got %v", retrievedAdmin.Name, "system:admin")
	}

}
Example #2
0
// TestOAuthOIDC checks CLI password login against an OIDC provider
func TestOAuthOIDC(t *testing.T) {

	tokenCalled := false
	userinfoCalled := false
	expectedTokenPost := url.Values{
		"grant_type":    []string{"password"},
		"client_id":     []string{"myclient"},
		"client_secret": []string{"mysecret"},
		"username":      []string{"mylogin"},
		"password":      []string{"mypassword"},
		"scope":         []string{"openid scope1 scope2"},
	}

	// id_token made at https://jwt.io/
	// {
	// 	"sub": "mysub",
	// 	"name": "John Doe",
	// 	"myidclaim": "myid",
	// 	"myemailclaim":"myemail",
	// }
	tokenResponse := `{
		"token_type":   "bearer",
		"access_token": "12345",
		"id_token":     "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJteXN1YiIsIm5hbWUiOiJKb2huIERvZSIsIm15aWRjbGFpbSI6Im15aWQiLCJteWVtYWlsY2xhaW0iOiJteWVtYWlsIn0.yMx2ZQw8Su641H_kO8ec_tFaysrFEc9uFUFm4ZbLGHw"
	}`

	// Additional claims in userInfo (sub claim must match)
	userinfoResponse := `{
		"sub": "mysub",
	 	"mynameclaim":"myname",
	 	"myusernameclaim":"myusername"
	}`

	// Write cert we're going to use to verify OIDC server requests
	caFile, err := ioutil.TempFile("", "test.crt")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	defer os.Remove(caFile.Name())
	if err := ioutil.WriteFile(caFile.Name(), oidcLocalhostCert, os.FileMode(0600)); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Get master config
	testutil.RequireEtcd(t)

	masterOptions, err := testserver.DefaultMasterOptions()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Set up a dummy OIDC server
	oidcServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.String() {
		case "/token":
			if r.Method != "POST" {
				t.Fatalf("Expected POST to /token, got %s", r.Method)
			}
			if err := r.ParseForm(); err != nil {
				t.Fatalf("Error parsing form POSTed to /token: %v", err)
			}
			if !reflect.DeepEqual(r.PostForm, expectedTokenPost) {
				t.Fatalf("Expected\n%#v\ngot\n%#v", expectedTokenPost, r.PostForm)
			}

			w.Write([]byte(tokenResponse))
			tokenCalled = true

		case "/userinfo":
			if r.Header.Get("Authorization") != "Bearer 12345" {
				t.Fatalf("Expected authorization header, got %#v", r.Header)
			}
			w.Write([]byte(userinfoResponse))
			userinfoCalled = true

		default:
			t.Fatalf("Unexpected OIDC request: %v", r.URL.String())
		}
	}))
	cert, err := tls.X509KeyPair(oidcLocalhostCert, oidcLocalhostKey)
	oidcServer.TLS = &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	oidcServer.StartTLS()
	defer oidcServer.Close()

	masterOptions.OAuthConfig.IdentityProviders[0] = configapi.IdentityProvider{
		Name:            "oidc",
		UseAsChallenger: true,
		UseAsLogin:      true,
		MappingMethod:   "claim",
		Provider: &configapi.OpenIDIdentityProvider{
			CA:           caFile.Name(),
			ClientID:     "myclient",
			ClientSecret: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Value: "mysecret"}},
			ExtraScopes:  []string{"scope1", "scope2"},
			URLs: configapi.OpenIDURLs{
				Authorize: oidcServer.URL + "/authorize",
				Token:     oidcServer.URL + "/token",
				UserInfo:  oidcServer.URL + "/userinfo",
			},
			Claims: configapi.OpenIDClaims{
				ID:                []string{"myidclaim"},
				Email:             []string{"myemailclaim"},
				Name:              []string{"mynameclaim"},
				PreferredUsername: []string{"myusernameclaim"},
			},
		},
	}

	// Start server
	clusterAdminKubeConfig, err := testserver.StartConfiguredMaster(masterOptions)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	clientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Get the master CA data for the login command
	masterCAFile := clientConfig.CAFile
	if masterCAFile == "" {
		// Write master ca data
		tmpFile, err := ioutil.TempFile("", "ca.crt")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		defer os.Remove(tmpFile.Name())
		if err := ioutil.WriteFile(tmpFile.Name(), clientConfig.CAData, os.FileMode(0600)); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		masterCAFile = tmpFile.Name()
	}

	// Attempt a login using a redirecting auth proxy
	loginOutput := &bytes.Buffer{}
	loginOptions := &cmd.LoginOptions{
		Server:             clientConfig.Host,
		CAFile:             masterCAFile,
		StartingKubeConfig: &clientcmdapi.Config{},
		Reader:             bytes.NewBufferString("mylogin\nmypassword\n"),
		Out:                loginOutput,
	}
	if err := loginOptions.GatherInfo(); err != nil {
		t.Fatalf("Error logging in: %v\n%v", err, loginOutput.String())
	}
	if loginOptions.Username != "myusername" {
		t.Fatalf("Unexpected user after authentication: %#v", loginOptions)
	}
	if len(loginOptions.Config.BearerToken) == 0 {
		t.Fatalf("Expected token after authentication: %#v", loginOptions.Config)
	}

	// Ex
	userConfig := &restclient.Config{
		Host: clientConfig.Host,
		TLSClientConfig: restclient.TLSClientConfig{
			CAFile: clientConfig.CAFile,
			CAData: clientConfig.CAData,
		},
		BearerToken: loginOptions.Config.BearerToken,
	}
	userClient, err := client.New(userConfig)
	userWhoamiOptions := cmd.WhoAmIOptions{UserInterface: userClient.Users(), Out: ioutil.Discard}
	retrievedUser, err := userWhoamiOptions.WhoAmI()
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if retrievedUser.Name != "myusername" {
		t.Errorf("expected username %v, got %v", "myusername", retrievedUser.Name)
	}
	if retrievedUser.FullName != "myname" {
		t.Errorf("expected display name %v, got %v", "myname", retrievedUser.FullName)
	}
	if !reflect.DeepEqual([]string{"oidc:myid"}, retrievedUser.Identities) {
		t.Errorf("expected only oidc:myid identity, got %v", retrievedUser.Identities)
	}
}