Re-implement basic identity API for v0.2.0.
diff --git a/openstack/identity/requests.go b/openstack/identity/requests.go
index 0012a17..dbd367e 100644
--- a/openstack/identity/requests.go
+++ b/openstack/identity/requests.go
@@ -4,42 +4,56 @@
 	"github.com/racker/perigee"
 )
 
+// AuthResults encapsulates the raw results from an authentication request.
+// As OpenStack allows extensions to influence the structure returned in
+// ways that Gophercloud cannot predict at compile-time, you should use
+// type-safe accessors to work with the data represented by this type,
+// such as ServiceCatalog() and Token().
 type AuthResults map[string]interface{}
 
-// AuthOptions lets anyone calling Authenticate() supply the required access credentials.
-// At present, only Identity V2 API support exists; therefore, only Username, Password,
-// and optionally, TenantId are provided.  If future Identity API versions become available,
-// alternative fields unique to those versions may appear here.
+// AuthOptions lets anyone calling Authenticate() supply the required access
+// credentials.  At present, only Identity V2 API support exists; therefore,
+// only Username, Password, and optionally, TenantId are provided.  If future
+// Identity API versions become available, alternative fields unique to those
+// versions may appear here.
+//
+// Endpoint specifies the HTTP endpoint offering the Identity V2 API.
+// Required.
+//
+// Username is required if using Identity V2 API.  Consult with your provider's
+// control panel to discover your account's username.
+//
+// At most one of Password or ApiKey is required if using Identity V2 API.
+// Consult with your provider's control panel to discover your account's
+// preferred method of authentication.
+//
+// The TenantId and TenantName fields are optional for the Identity V2 API.
+// Some providers allow you to specify a TenantName instead of the TenantId.
+// Some require both.  Your provider's authentication policies will determine
+// how these fields influence authentication.
+//
+// AllowReauth should be set to true if you grant permission for Gophercloud to
+// cache your credentials in memory, and to allow Gophercloud to attempt to
+// 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.
 type AuthOptions struct {
-	// Endpoint specifies the HTTP endpoint offering the Identity V2 API.
-	// Required.
-	Endpoint string
-
-	// Username is required if using Identity V2 API.
-	// Consult with your provider's control panel to discover your
-	// account's username.
-	Username string
-
-	// At most one of Password or ApiKey is required if using Identity V2 API.
-	// Consult with your provider's control panel to discover your
-	// account's preferred method of authentication.
+	Endpoint         string
+	Username         string
 	Password, ApiKey string
-
-	// The TenantId field is optional for the Identity V2 API.
-	TenantId string
-
-	// The TenantName can be specified instead of the TenantId
-	TenantName string
-
-	// AllowReauth should be set to true if you grant permission for Gophercloud to cache
-	// your credentials in memory, and to allow Gophercloud to attempt to 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.
-	AllowReauth bool
+	TenantId         string
+	TenantName       string
+	AllowReauth      bool
 }
 
+// Authenticate passes the supplied credentials to the OpenStack provider for authentication.
+// If successful, the caller may use Token() to retrieve the authentication token,
+// and ServiceCatalog() to retrieve the set of services available to the API user.
 func Authenticate(options AuthOptions) (AuthResults, error) {
+	type AuthContainer struct {
+		Auth auth `json:"auth"`
+	}
+
 	var ar AuthResults
 
 	if options.Endpoint == "" {
@@ -50,7 +64,8 @@
 		return nil, ErrCredentials
 	}
 
-	err := perigee.Post(options.Endpoint, perigee.Options{
+	url := options.Endpoint + "/tokens"
+	err := perigee.Post(url, perigee.Options{
 		ReqBody: &AuthContainer{
 			Auth: getAuthCredentials(options),
 		},
@@ -59,9 +74,9 @@
 	return ar, err
 }
 
-func getAuthCredentials(options AuthOptions) Auth {
+func getAuthCredentials(options AuthOptions) auth {
 	if options.ApiKey == "" {
-		return Auth{
+		return auth{
 			PasswordCredentials: &struct {
 				Username string `json:"username"`
 				Password string `json:"password"`
@@ -73,7 +88,7 @@
 			TenantName: options.TenantName,
 		}
 	} else {
-		return Auth{
+		return auth{
 			ApiKeyCredentials: &struct {
 				Username string `json:"username"`
 				ApiKey   string `json:"apiKey"`
@@ -87,17 +102,19 @@
 	}
 }
 
-// AuthContainer provides a JSON encoding wrapper for passing credentials to the Identity
-// service.  You will not work with this structure directly.
-type AuthContainer struct {
-	Auth Auth `json:"auth"`
-}
-
-// Auth provides a JSON encoding wrapper for passing credentials to the Identity
-// service.  You will not work with this structure directly.
-type Auth struct {
+type auth struct {
 	PasswordCredentials interface{} `json:"passwordCredentials,omitempty"`
 	ApiKeyCredentials   interface{} `json:"RAX-KSKEY:apiKeyCredentials,omitempty"`
 	TenantId            string      `json:"tenantId,omitempty"`
 	TenantName          string      `json:"tenantName,omitempty"`
 }
+
+func GetExtensions(options AuthOptions) (ExtensionsResult, error) {
+	var exts ExtensionsResult
+
+	url := options.Endpoint + "/extensions"
+	err := perigee.Get(url, perigee.Options{
+		Results: &exts,
+	})
+	return exts, err
+}