blob: 0f7c6332e60dcd66eeb1a688eeeb2effdf8c515c [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"
5)
6
Samuel A. Falvo II4e895182013-06-26 15:44:18 -07007// AuthOptions lets anyone calling Authenticate() supply the required access credentials.
8// At present, only Identity V2 API support exists; therefore, only Username, Password,
9// and optionally, TenantId are provided. If future Identity API versions become available,
10// alternative fields unique to those versions may appear here.
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -070011type AuthOptions struct {
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070012 // Username and Password are required if using Identity V2 API.
13 // Consult with your provider's control panel to discover your
14 // account's username and password.
15 Username, Password string
16
Rafael Garciae4a550e2013-12-06 17:00:32 -030017 // ApiKey used for providers that support Api Key authentication
18 ApiKey string
19
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070020 // The TenantId field is optional for the Identity V2 API.
21 TenantId string
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070022
Justin Santa Barbara21682a42013-08-31 17:56:13 -070023 // The TenantName can be specified instead of the TenantId
24 TenantName string
25
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070026 // AllowReauth should be set to true if you grant permission for Gophercloud to cache
27 // your credentials in memory, and to allow Gophercloud to attempt to re-authenticate
28 // automatically if/when your token expires. If you set it to false, it will not cache
29 // these settings, but re-authentication will not be possible. This setting defaults
30 // to false.
31 AllowReauth bool
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -070032}
33
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070034// AuthContainer provides a JSON encoding wrapper for passing credentials to the Identity
35// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070036type AuthContainer struct {
37 Auth Auth `json:"auth"`
38}
39
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070040// Auth provides a JSON encoding wrapper for passing credentials to the Identity
41// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070042type Auth struct {
Rafael Garciae4a550e2013-12-06 17:00:32 -030043 PasswordCredentials *PasswordCredentials `json:"passwordCredentials,omitempty"`
44 ApiKeyCredentials *ApiKeyCredentials `json:"RAX-KSKEY:apiKeyCredentials,omitempty"`
Rafael Garcia752cb332013-12-12 22:16:58 -030045 TenantId string `json:"tenantId,omitempty"`
46 TenantName string `json:"tenantName,omitempty"`
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070047}
48
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070049// PasswordCredentials provides a JSON encoding wrapper for passing credentials to the Identity
50// service. You will not work with this structure directly.
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070051type PasswordCredentials struct {
52 Username string `json:"username"`
53 Password string `json:"password"`
54}
55
Rafael Garciae4a550e2013-12-06 17:00:32 -030056type ApiKeyCredentials struct {
57 Username string `json:"username"`
Rafael Garcia752cb332013-12-12 22:16:58 -030058 ApiKey string `json:"apiKey"`
Rafael Garciae4a550e2013-12-06 17:00:32 -030059}
60
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070061// Access encapsulates the API token and its relevant fields, as well as the
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -070062// services catalog that Identity API returns once authenticated.
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070063type Access struct {
64 Token Token
65 ServiceCatalog []CatalogEntry
66 User User
Samuel A. Falvo II20f1aa42013-07-31 14:32:03 -070067 provider Provider `json:"-"`
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -070068 options AuthOptions `json:"-"`
Samuel A. Falvo II20f1aa42013-07-31 14:32:03 -070069 context *Context `json:"-"`
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070070}
71
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -070072// Token encapsulates an authentication token and when it expires. It also includes
73// tenant information if available.
74type Token struct {
75 Id, Expires string
76 Tenant Tenant
77}
78
79// Tenant encapsulates tenant authentication information. If, after authentication,
80// no tenant information is supplied, both Id and Name will be "".
81type Tenant struct {
82 Id, Name string
83}
84
85// User encapsulates the user credentials, and provides visibility in what
86// the user can do through its role assignments.
87type User struct {
88 Id, Name string
89 XRaxDefaultRegion string `json:"RAX-AUTH:defaultRegion"`
90 Roles []Role
91}
92
93// Role encapsulates a permission that a user can rely on.
94type Role struct {
95 Description, Id, Name string
96}
97
98// CatalogEntry encapsulates a service catalog record.
99type CatalogEntry struct {
100 Name, Type string
101 Endpoints []EntryEndpoint
102}
103
104// EntryEndpoint encapsulates how to get to the API of some service.
105type EntryEndpoint struct {
106 Region, TenantId string
107 PublicURL, InternalURL string
108 VersionId, VersionInfo, VersionList string
109}
110
Rafael Garciae4a550e2013-12-06 17:00:32 -0300111//
112func getAuthCredentials(options AuthOptions) Auth {
Rafael Garcia752cb332013-12-12 22:16:58 -0300113 if options.ApiKey == "" {
Rafael Garciae4a550e2013-12-06 17:00:32 -0300114 return Auth{
115 PasswordCredentials: &PasswordCredentials{
116 Username: options.Username,
117 Password: options.Password,
118 },
119 TenantId: options.TenantId,
120 TenantName: options.TenantName,
Rafael Garcia752cb332013-12-12 22:16:58 -0300121 }
Rafael Garciae4a550e2013-12-06 17:00:32 -0300122 } else {
123 return Auth{
124 ApiKeyCredentials: &ApiKeyCredentials{
125 Username: options.Username,
Rafael Garcia752cb332013-12-12 22:16:58 -0300126 ApiKey: options.ApiKey,
Rafael Garciae4a550e2013-12-06 17:00:32 -0300127 },
128 TenantId: options.TenantId,
129 TenantName: options.TenantName,
Rafael Garcia752cb332013-12-12 22:16:58 -0300130 }
Rafael Garciae4a550e2013-12-06 17:00:32 -0300131 }
132}
133
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700134// papersPlease contains the common logic between authentication and re-authentication.
135// The name, obviously a joke on the process of authentication, was chosen because
136// of how many other entities exist in the program containing the word Auth or Authorization.
137// I didn't need another one.
138func (c *Context) papersPlease(p Provider, options AuthOptions) (*Access, error) {
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700139 var access *Access
140
Rafael Garciae4a550e2013-12-06 17:00:32 -0300141 if (options.Username == "") || (options.Password == "" && options.ApiKey == "") {
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700142 return nil, ErrCredentials
143 }
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700144
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700145 err := perigee.Post(p.AuthEndpoint, perigee.Options{
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700146 CustomClient: c.httpClient,
Samuel A. Falvo II839428e2013-06-25 18:02:24 -0700147 ReqBody: &AuthContainer{
Rafael Garciae4a550e2013-12-06 17:00:32 -0300148 Auth: getAuthCredentials(options),
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700149 },
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700150 Results: &struct {
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700151 Access **Access `json:"access"`
152 }{
153 &access,
154 },
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700155 })
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700156 if err == nil {
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700157 access.options = options
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700158 access.provider = p
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700159 access.context = c
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700160 }
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700161 return access, err
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -0700162}
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700163
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700164// Authenticate() grants access to the OpenStack-compatible provider API.
165//
166// Providers are identified through a unique key string.
167// See the RegisterProvider() method for more details.
168//
169// The supplied AuthOptions instance allows the client to specify only those credentials
170// relevant for the authentication request. At present, support exists for OpenStack
171// Identity V2 API only; support for V3 will become available as soon as documentation for it
172// becomes readily available.
173//
174// For Identity V2 API requirements, you must provide at least the Username and Password
175// options. The TenantId field is optional, and defaults to "".
176func (c *Context) Authenticate(provider string, options AuthOptions) (*Access, error) {
177 p, err := c.ProviderByName(provider)
178 if err != nil {
179 return nil, err
180 }
181 return c.papersPlease(p, options)
182}
183
184// Reauthenticate attempts to reauthenticate using the configured access credentials, if
185// allowed. This method takes no action unless your AuthOptions has the AllowReauth flag
186// set to true.
187func (a *Access) Reauthenticate() error {
188 var other *Access
189 var err error
190
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700191 if a.options.AllowReauth {
192 other, err = a.context.papersPlease(a.provider, a.options)
Samuel A. Falvo IIfb586692013-07-16 17:00:14 -0700193 if err == nil {
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700194 *a = *other
195 }
196 }
197 return err
198}
199
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700200// See AccessProvider interface definition for details.
201func (a *Access) FirstEndpointUrlByCriteria(ac ApiCriteria) string {
202 ep := FindFirstEndpointByCriteria(a.ServiceCatalog, ac)
203 urls := []string{ep.PublicURL, ep.InternalURL}
204 return urls[ac.UrlChoice]
205}
Samuel A. Falvo IIbc0d54a2013-07-08 14:45:21 -0700206
207// See AccessProvider interface definition for details.
208func (a *Access) AuthToken() string {
209 return a.Token.Id
210}
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700211
212// See AccessProvider interface definition for details.
213func (a *Access) Revoke(tok string) error {
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700214 url := a.provider.AuthEndpoint + "/" + tok
215 err := perigee.Delete(url, perigee.Options{
216 MoreHeaders: map[string]string{
217 "X-Auth-Token": a.AuthToken(),
218 },
219 OkCodes: []int{204},
220 })
221 return err
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700222}
Samuel A. Falvo IIcfb352a2013-11-19 14:39:37 -0800223
224// See ServiceCatalogerForIdentityV2 interface definition for details.
225// Note that the raw slice is returend; be careful not to alter the fields of any members,
226// for other components of Gophercloud may depend upon them.
227// If this becomes a problem in the future,
228// a future revision may return a deep-copy of the service catalog instead.
229func (a *Access) V2ServiceCatalog() []CatalogEntry {
230 return a.ServiceCatalog
231}