blob: f98c4cce6a343abcca15713c776ac6d926b8bf06 [file] [log] [blame]
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -07001package gophercloud
2
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -07003import (
4 "github.com/racker/perigee"
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -07005 "fmt"
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -07006)
7
Samuel A. Falvo II4e895182013-06-26 15:44:18 -07008// AuthOptions lets anyone calling Authenticate() supply the required access credentials.
9// At present, only Identity V2 API support exists; therefore, only Username, Password,
10// and optionally, TenantId are provided. If future Identity API versions become available,
11// alternative fields unique to those versions may appear here.
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -070012type AuthOptions struct {
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070013 // Username and Password are required if using Identity V2 API.
14 // Consult with your provider's control panel to discover your
15 // account's username and password.
16 Username, Password string
17
18 // The TenantId field is optional for the Identity V2 API.
19 TenantId string
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070020
21 // AllowReauth should be set to true if you grant permission for Gophercloud to cache
22 // your credentials in memory, and to allow Gophercloud to attempt to re-authenticate
23 // automatically if/when your token expires. If you set it to false, it will not cache
24 // these settings, but re-authentication will not be possible. This setting defaults
25 // to false.
26 AllowReauth bool
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -070027}
28
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070029// AuthContainer provides a JSON encoding wrapper for passing credentials to the Identity
30// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070031type AuthContainer struct {
32 Auth Auth `json:"auth"`
33}
34
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070035// Auth provides a JSON encoding wrapper for passing credentials to the Identity
36// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070037type Auth struct {
38 PasswordCredentials PasswordCredentials `json:"passwordCredentials"`
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070039 TenantId string `json:"tenantId,omitempty"`
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070040}
41
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070042// PasswordCredentials provides a JSON encoding wrapper for passing credentials to the Identity
43// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070044type PasswordCredentials struct {
45 Username string `json:"username"`
46 Password string `json:"password"`
47}
48
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070049// Access encapsulates the API token and its relevant fields, as well as the
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -070050// services catalog that Identity API returns once authenticated.
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070051type Access struct {
52 Token Token
53 ServiceCatalog []CatalogEntry
54 User User
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -070055 provider Provider `json:"-"`
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070056 options AuthOptions `json:"-"`
57 context *Context `json:"-"`
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070058}
59
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070060// Token encapsulates an authentication token and when it expires. It also includes
61// tenant information if available.
62type Token struct {
63 Id, Expires string
64 Tenant Tenant
65}
66
67// Tenant encapsulates tenant authentication information. If, after authentication,
68// no tenant information is supplied, both Id and Name will be "".
69type Tenant struct {
70 Id, Name string
71}
72
73// User encapsulates the user credentials, and provides visibility in what
74// the user can do through its role assignments.
75type User struct {
76 Id, Name string
77 XRaxDefaultRegion string `json:"RAX-AUTH:defaultRegion"`
78 Roles []Role
79}
80
81// Role encapsulates a permission that a user can rely on.
82type Role struct {
83 Description, Id, Name string
84}
85
86// CatalogEntry encapsulates a service catalog record.
87type CatalogEntry struct {
88 Name, Type string
89 Endpoints []EntryEndpoint
90}
91
92// EntryEndpoint encapsulates how to get to the API of some service.
93type EntryEndpoint struct {
94 Region, TenantId string
95 PublicURL, InternalURL string
96 VersionId, VersionInfo, VersionList string
97}
98
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070099// papersPlease contains the common logic between authentication and re-authentication.
100// The name, obviously a joke on the process of authentication, was chosen because
101// of how many other entities exist in the program containing the word Auth or Authorization.
102// I didn't need another one.
103func (c *Context) papersPlease(p Provider, options AuthOptions) (*Access, error) {
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700104 var access *Access
105
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700106 if (options.Username == "") || (options.Password == "") {
107 return nil, ErrCredentials
108 }
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700109
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700110 err := perigee.Post(p.AuthEndpoint, perigee.Options{
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700111 CustomClient: c.httpClient,
Samuel A. Falvo II839428e2013-06-25 18:02:24 -0700112 ReqBody: &AuthContainer{
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700113 Auth: Auth{
114 PasswordCredentials: PasswordCredentials{
115 Username: options.Username,
116 Password: options.Password,
117 },
118 TenantId: options.TenantId,
119 },
120 },
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700121 Results: &struct {
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700122 Access **Access `json:"access"`
123 }{
124 &access,
125 },
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700126 })
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700127 if err == nil {
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700128 access.options = options
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700129 access.provider = p
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700130 access.context = c
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700131 }
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700132 return access, err
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -0700133}
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700134
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700135// Authenticate() grants access to the OpenStack-compatible provider API.
136//
137// Providers are identified through a unique key string.
138// See the RegisterProvider() method for more details.
139//
140// The supplied AuthOptions instance allows the client to specify only those credentials
141// relevant for the authentication request. At present, support exists for OpenStack
142// Identity V2 API only; support for V3 will become available as soon as documentation for it
143// becomes readily available.
144//
145// For Identity V2 API requirements, you must provide at least the Username and Password
146// options. The TenantId field is optional, and defaults to "".
147func (c *Context) Authenticate(provider string, options AuthOptions) (*Access, error) {
148 p, err := c.ProviderByName(provider)
149 if err != nil {
150 return nil, err
151 }
152 return c.papersPlease(p, options)
153}
154
155// Reauthenticate attempts to reauthenticate using the configured access credentials, if
156// allowed. This method takes no action unless your AuthOptions has the AllowReauth flag
157// set to true.
158func (a *Access) Reauthenticate() error {
159 var other *Access
160 var err error
161
162 fmt.Printf("**\n %#v\n", a.options)
163 if a.options.AllowReauth {
164 other, err = a.context.papersPlease(a.provider, a.options)
165 if err != nil {
166 fmt.Println("NEW NEW: ", other.AuthToken())
167 *a = *other
168 }
169 }
170 return err
171}
172
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700173// See AccessProvider interface definition for details.
174func (a *Access) FirstEndpointUrlByCriteria(ac ApiCriteria) string {
175 ep := FindFirstEndpointByCriteria(a.ServiceCatalog, ac)
176 urls := []string{ep.PublicURL, ep.InternalURL}
177 return urls[ac.UrlChoice]
178}
Samuel A. Falvo IIbc0d54a2013-07-08 14:45:21 -0700179
180// See AccessProvider interface definition for details.
181func (a *Access) AuthToken() string {
182 return a.Token.Id
183}
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700184
185// See AccessProvider interface definition for details.
186func (a *Access) Revoke(tok string) error {
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700187 url := a.provider.AuthEndpoint + "/" + tok
188 err := perigee.Delete(url, perigee.Options{
189 MoreHeaders: map[string]string{
190 "X-Auth-Token": a.AuthToken(),
191 },
192 OkCodes: []int{204},
193 })
194 return err
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700195}