Shuffle around authentication methods.

I'd like to be able to explicitly authenticated with a certain version.
diff --git a/openstack/client.go b/openstack/client.go
index 7e3850e..98092c8 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -18,46 +18,84 @@
 	v30 = "v3.0"
 )
 
-// NewClient authenticates to an OpenStack cloud with the provided credentials.
+// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by authOptions, acquires a token, and
+// returns a Client instance that's ready to operate.
 // It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses
 // the most recent identity service available to proceed.
-func NewClient(authOptions gophercloud.AuthOptions) (*Client, error) {
+func AuthenticatedClient(authOptions gophercloud.AuthOptions) (*Client, error) {
+	client := NewClient(authOptions)
+	err := client.Authenticate()
+	if err != nil {
+		return nil, err
+	}
+	return client, nil
+}
+
+// NewClient prepares an unauthenticated Client instance.
+// Most users will probably prefer using the AuthenticatedClient function instead.
+// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
+// for example.
+func NewClient(authOptions gophercloud.AuthOptions) *Client {
+	return &Client{
+		ProviderClient: gophercloud.ProviderClient{
+			Options: authOptions,
+		},
+	}
+}
+
+// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint.
+func (client *Client) Authenticate() error {
 	versions := []*utils.Version{
 		&utils.Version{ID: v20, Priority: 20},
 		&utils.Version{ID: v30, Priority: 30},
 	}
 
-	chosen, endpoint, err := utils.ChooseVersion(authOptions.IdentityEndpoint, versions)
+	chosen, endpoint, err := utils.ChooseVersion(client.ProviderClient.Options.IdentityEndpoint, versions)
 	if err != nil {
-		return nil, err
-	}
-
-	client := Client{
-		ProviderClient: gophercloud.ProviderClient{
-			IdentityEndpoint: endpoint,
-			Options:          authOptions,
-		},
+		return err
 	}
 
 	switch chosen.ID {
 	case v20:
+		return client.authenticateV2(endpoint)
 	case v30:
-		identityClient := identity3.NewClient(&client.ProviderClient)
-		token, err := identityClient.Authenticate(authOptions)
-		if err != nil {
-			return nil, err
-		}
-
-		client.ProviderClient.TokenID = token.ID
+		return client.authenticateV3(endpoint)
 	default:
-		// The switch must be out of sync with "versions".
-		return nil, errors.New("Wat")
+		// The switch statement must be out of date from the versions list.
+		return errors.New("Wat")
+	}
+}
+
+// AuthenticateV2 acquires a token explicitly from the v2.0 identity API.
+func (client *Client) AuthenticateV2() error {
+	endpoint := client.ProviderClient.Options.IdentityEndpoint + "/v2.0"
+	return client.authenticateV2(endpoint)
+}
+
+func (client *Client) authenticateV2(endpoint string) error {
+	return errors.New("Not implemented yet.")
+}
+
+// AuthenticateV3 acquires a token explicitly from the v3.0 identity API.
+func (client *Client) AuthenticateV3() error {
+	endpoint := client.ProviderClient.Options.IdentityEndpoint + "/v3"
+	return client.authenticateV3(endpoint)
+}
+
+func (client *Client) authenticateV3(endpoint string) error {
+	identityClient := identity3.NewClient(&client.ProviderClient, endpoint)
+	token, err := identityClient.GetToken(client.ProviderClient.Options)
+	if err != nil {
+		return err
 	}
 
-	return &client, nil
+	client.ProviderClient.TokenID = token.ID
+
+	return nil
 }
 
 // NewIdentityV3 explicitly accesses the v3 identity service.
 func (client *Client) NewIdentityV3() (*identity3.Client, error) {
-	return identity3.NewClient(&client.ProviderClient), nil
+	endpoint := client.ProviderClient.Options.IdentityEndpoint + "/v3"
+	return identity3.NewClient(&client.ProviderClient, endpoint), nil
 }
diff --git a/openstack/identity/v3/client.go b/openstack/identity/v3/client.go
index 984d03e..96e6f5d 100644
--- a/openstack/identity/v3/client.go
+++ b/openstack/identity/v3/client.go
@@ -20,17 +20,17 @@
 }
 
 // NewClient creates a new client associated with the v3 identity service of a provider.
-func NewClient(provider *gophercloud.ProviderClient) *Client {
+func NewClient(provider *gophercloud.ProviderClient, endpoint string) *Client {
 	return &Client{
 		ServiceClient: gophercloud.ServiceClient{
 			ProviderClient: *provider,
-			Endpoint:       provider.IdentityEndpoint,
+			Endpoint:       endpoint,
 		},
 	}
 }
 
-// Authenticate provides the supplied credentials to an identity v3 endpoint and attempts to acquire a token.
-func (c *Client) Authenticate(authOptions gophercloud.AuthOptions) (*Token, error) {
+// GetToken provides the supplied credentials to an identity v3 endpoint and attempts to acquire a token.
+func (c *Client) GetToken(authOptions gophercloud.AuthOptions) (*Token, error) {
 	c.ServiceClient.ProviderClient.Options = authOptions
 
 	result, err := tokens.Create(&c.ServiceClient, nil)
@@ -48,8 +48,5 @@
 		return nil, err
 	}
 
-	return &Token{
-		ID:        tokenID,
-		ExpiresAt: expiresAt,
-	}, nil
+	return &Token{ID: tokenID, ExpiresAt: expiresAt}, nil
 }
diff --git a/openstack/identity/v3/client_test.go b/openstack/identity/v3/client_test.go
index c9cf3c2..6747660 100644
--- a/openstack/identity/v3/client_test.go
+++ b/openstack/identity/v3/client_test.go
@@ -26,7 +26,7 @@
 	}
 }
 
-func TestAuthentication(t *testing.T) {
+func TestGetToken(t *testing.T) {
 	testhelper.SetupHTTP()
 	defer testhelper.TeardownHTTP()
 	const ID = "aaaa1111"
@@ -43,7 +43,7 @@
 	}
 	client := NewClient(provider)
 
-	token, err := client.Authenticate(gophercloud.AuthOptions{UserID: "me", Password: "swordfish"})
+	token, err := client.GetToken(gophercloud.AuthOptions{UserID: "me", Password: "swordfish"})
 	if err != nil {
 		t.Errorf("Unexpected error from authentication: %v", err)
 	}