Swauth Support (#65)
* Swauth Support
Swauth is an internal authentication system for Swift. This commit adds
support for Swauth in a way that still enables the resulting
*gophercloud.ServiceClient to still be able to use the existing ObjectStorage
API calls.
* Swauth updates for consistency
* Marking required fields for Swauth
diff --git a/openstack/objectstorage/v1/swauth/requests.go b/openstack/objectstorage/v1/swauth/requests.go
new file mode 100644
index 0000000..ce4bf9a
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/requests.go
@@ -0,0 +1,70 @@
+package swauth
+
+import "github.com/gophercloud/gophercloud"
+
+// AuthOptsBuilder describes struct types that can be accepted by the Auth call.
+// The AuthOpts struct in this package does.
+type AuthOptsBuilder interface {
+ ToAuthOptsMap() (map[string]string, error)
+}
+
+// AuthOpts specifies an authentication request.
+type AuthOpts struct {
+ // User is an Swauth-based username in username:tenant format.
+ User string `h:"X-Auth-User" required:"true"`
+ // Key is a secret/password to authenticate the User with.
+ Key string `h:"X-Auth-Key" required:"true"`
+}
+
+// ToAuthOptsMap formats an AuthOpts structure into a request body.
+func (opts AuthOpts) ToAuthOptsMap() (map[string]string, error) {
+ return gophercloud.BuildHeaders(opts)
+}
+
+// Auth performs an authentication request for a Swauth-based user.
+func Auth(c *gophercloud.ProviderClient, opts AuthOptsBuilder) (r GetAuthResult) {
+ h := make(map[string]string)
+
+ if opts != nil {
+ headers, err := opts.ToAuthOptsMap()
+ if err != nil {
+ r.Err = err
+ return
+ }
+
+ for k, v := range headers {
+ h[k] = v
+ }
+ }
+
+ resp, err := c.Request("GET", getURL(c), &gophercloud.RequestOpts{
+ MoreHeaders: h,
+ OkCodes: []int{200},
+ })
+
+ if resp != nil {
+ r.Header = resp.Header
+ }
+
+ r.Err = err
+
+ return r
+}
+
+// NewObjectStorageV1 creates a Swauth-authenticated *gophercloud.ServiceClient
+// client that can issue ObjectStorage-based API calls.
+func NewObjectStorageV1(pc *gophercloud.ProviderClient, authOpts AuthOpts) (*gophercloud.ServiceClient, error) {
+ auth, err := Auth(pc, authOpts).Extract()
+ if err != nil {
+ return nil, err
+ }
+
+ swiftClient := &gophercloud.ServiceClient{
+ ProviderClient: pc,
+ Endpoint: auth.StorageURL,
+ }
+
+ swiftClient.TokenID = auth.Token
+
+ return swiftClient, nil
+}
diff --git a/openstack/objectstorage/v1/swauth/results.go b/openstack/objectstorage/v1/swauth/results.go
new file mode 100644
index 0000000..294c43c
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/results.go
@@ -0,0 +1,27 @@
+package swauth
+
+import (
+ "github.com/gophercloud/gophercloud"
+)
+
+// GetAuthResult temporarily contains the response from a Swauth
+// authentication call.
+type GetAuthResult struct {
+ gophercloud.HeaderResult
+}
+
+// AuthResult contains the authentication information from a Swauth
+// authentication request.
+type AuthResult struct {
+ Token string `json:"X-Auth-Token"`
+ StorageURL string `json:"X-Storage-Url"`
+ CDNURL string `json:"X-CDN-Management-Url"`
+}
+
+// Extract is a method that attempts to interpret any Swauth authentication
+// response as a AuthResult struct.
+func (r GetAuthResult) Extract() (*AuthResult, error) {
+ var s *AuthResult
+ err := r.ExtractInto(&s)
+ return s, err
+}
diff --git a/openstack/objectstorage/v1/swauth/testing/doc.go b/openstack/objectstorage/v1/swauth/testing/doc.go
new file mode 100644
index 0000000..7603f83
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/testing/doc.go
@@ -0,0 +1 @@
+package testing
diff --git a/openstack/objectstorage/v1/swauth/testing/fixtures.go b/openstack/objectstorage/v1/swauth/testing/fixtures.go
new file mode 100644
index 0000000..f7cbc93
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/testing/fixtures.go
@@ -0,0 +1,29 @@
+package testing
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth"
+ th "github.com/gophercloud/gophercloud/testhelper"
+)
+
+// AuthResult is the expected result of AuthOutput
+var AuthResult = swauth.AuthResult{
+ Token: "AUTH_tk6223e6071f8f4299aa334b48015484a1",
+ StorageURL: "http://127.0.0.1:8080/v1/AUTH_test",
+}
+
+// HandleAuthSuccessfully configures the test server to respond to an Auth request.
+func HandleAuthSuccessfully(t *testing.T, authOpts swauth.AuthOpts) {
+ th.Mux.HandleFunc("/auth/v1.0", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-User", authOpts.User)
+ th.TestHeader(t, r, "X-Auth-Key", authOpts.Key)
+
+ w.Header().Add("X-Auth-Token", AuthResult.Token)
+ w.Header().Add("X-Storage-Url", AuthResult.StorageURL)
+ fmt.Fprintf(w, "")
+ })
+}
diff --git a/openstack/objectstorage/v1/swauth/testing/requests_test.go b/openstack/objectstorage/v1/swauth/testing/requests_test.go
new file mode 100644
index 0000000..57b5034
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/testing/requests_test.go
@@ -0,0 +1,27 @@
+package testing
+
+import (
+ "testing"
+
+ "github.com/gophercloud/gophercloud/openstack"
+ "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth"
+ th "github.com/gophercloud/gophercloud/testhelper"
+)
+
+func TestAuth(t *testing.T) {
+ authOpts := swauth.AuthOpts{
+ User: "test:tester",
+ Key: "testing",
+ }
+
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleAuthSuccessfully(t, authOpts)
+
+ providerClient, err := openstack.NewClient(th.Endpoint())
+ th.AssertNoErr(t, err)
+
+ swiftClient, err := swauth.NewObjectStorageV1(providerClient, authOpts)
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, swiftClient.TokenID, AuthResult.Token)
+}
diff --git a/openstack/objectstorage/v1/swauth/urls.go b/openstack/objectstorage/v1/swauth/urls.go
new file mode 100644
index 0000000..a30cabd
--- /dev/null
+++ b/openstack/objectstorage/v1/swauth/urls.go
@@ -0,0 +1,7 @@
+package swauth
+
+import "github.com/gophercloud/gophercloud"
+
+func getURL(c *gophercloud.ProviderClient) string {
+ return c.IdentityBase + "auth/v1.0"
+}