Merge pull request #373 from jrperritt/auto-reauth

Auto reauth; Closes #152
diff --git a/auth_options.go b/auth_options.go
index 19ce5d4..9819e45 100644
--- a/auth_options.go
+++ b/auth_options.go
@@ -42,7 +42,5 @@
 	// re-authenticate automatically if/when your token expires.  If you set it to
 	// false, it will not cache these settings, but re-authentication will not be
 	// possible.  This setting defaults to false.
-	//
-	// This setting is speculative and is currently not respected!
 	AllowReauth bool
 }
diff --git a/openstack/client.go b/openstack/client.go
index 63e07b8..6818d9d 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -107,6 +107,11 @@
 		return err
 	}
 
+	if options.AllowReauth {
+		client.ReauthFunc = func() error {
+			return AuthenticateV2(client, options)
+		}
+	}
 	client.TokenID = token.ID
 	client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
 		return V2EndpointURL(catalog, opts)
@@ -133,6 +138,11 @@
 	}
 	client.TokenID = token.ID
 
+	if options.AllowReauth {
+		client.ReauthFunc = func() error {
+			return AuthenticateV3(client, options)
+		}
+	}
 	client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
 		return V3EndpointURL(v3Client, opts)
 	}
diff --git a/provider_client.go b/provider_client.go
index 3c65984..200ee0b 100644
--- a/provider_client.go
+++ b/provider_client.go
@@ -63,6 +63,11 @@
 
 	// UserAgent represents the User-Agent header in the HTTP request.
 	UserAgent UserAgent
+
+	// ReauthFunc is the function used to re-authenticate the user if the request
+	// fails with a 401 HTTP response code. This a needed because there may be multiple
+	// authentication functions for different Identity service versions.
+	ReauthFunc func() error
 }
 
 // AuthenticatedHeaders returns a map of HTTP headers that are common for all
@@ -179,6 +184,19 @@
 		return nil, err
 	}
 
+	if resp.StatusCode == http.StatusUnauthorized {
+		if client.ReauthFunc != nil {
+			err = client.ReauthFunc()
+			if err != nil {
+				return nil, fmt.Errorf("Error trying to re-authenticate: %s", err)
+			}
+			resp, err = client.Request(method, url, options)
+			if err != nil {
+				return nil, fmt.Errorf("Successfully re-authenticated, but got error executing request: %s", err)
+			}
+		}
+	}
+
 	// Validate the response code, if requested to do so.
 	if options.OkCodes != nil {
 		var ok bool
diff --git a/rackspace/client.go b/rackspace/client.go
index 039f446..8f1f34f 100644
--- a/rackspace/client.go
+++ b/rackspace/client.go
@@ -96,6 +96,11 @@
 		return err
 	}
 
+	if options.AllowReauth {
+		client.ReauthFunc = func() error {
+			return AuthenticateV2(client, options)
+		}
+	}
 	client.TokenID = token.ID
 	client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
 		return os.V2EndpointURL(catalog, opts)