blob: 003fb48e7171013eb46a8e5552f1ec2fb3754b86 [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
Matt Martz3927d842014-06-04 10:30:35 -0500140 access = new(Access)
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700141
Rafael Garciae4a550e2013-12-06 17:00:32 -0300142 if (options.Username == "") || (options.Password == "" && options.ApiKey == "") {
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -0700143 return nil, ErrCredentials
144 }
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700145
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700146 err := perigee.Post(p.AuthEndpoint, perigee.Options{
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700147 CustomClient: c.httpClient,
Samuel A. Falvo II839428e2013-06-25 18:02:24 -0700148 ReqBody: &AuthContainer{
Rafael Garciae4a550e2013-12-06 17:00:32 -0300149 Auth: getAuthCredentials(options),
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700150 },
Samuel A. Falvo II4e895182013-06-26 15:44:18 -0700151 Results: &struct {
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700152 Access **Access `json:"access"`
153 }{
154 &access,
155 },
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700156 })
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700157 if err == nil {
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700158 access.options = options
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700159 access.provider = p
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700160 access.context = c
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700161 }
Samuel A. Falvo IId1ee7982013-06-26 14:32:45 -0700162 return access, err
Samuel A. Falvo II1d3fa662013-06-25 15:29:32 -0700163}
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700164
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700165// Authenticate() grants access to the OpenStack-compatible provider API.
166//
167// Providers are identified through a unique key string.
168// See the RegisterProvider() method for more details.
169//
170// The supplied AuthOptions instance allows the client to specify only those credentials
171// relevant for the authentication request. At present, support exists for OpenStack
172// Identity V2 API only; support for V3 will become available as soon as documentation for it
173// becomes readily available.
174//
175// For Identity V2 API requirements, you must provide at least the Username and Password
176// options. The TenantId field is optional, and defaults to "".
177func (c *Context) Authenticate(provider string, options AuthOptions) (*Access, error) {
178 p, err := c.ProviderByName(provider)
179 if err != nil {
180 return nil, err
181 }
182 return c.papersPlease(p, options)
183}
184
185// Reauthenticate attempts to reauthenticate using the configured access credentials, if
186// allowed. This method takes no action unless your AuthOptions has the AllowReauth flag
187// set to true.
188func (a *Access) Reauthenticate() error {
189 var other *Access
190 var err error
191
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700192 if a.options.AllowReauth {
193 other, err = a.context.papersPlease(a.provider, a.options)
Samuel A. Falvo IIfb586692013-07-16 17:00:14 -0700194 if err == nil {
Samuel A. Falvo II9e64f6b2013-07-16 14:26:50 -0700195 *a = *other
196 }
197 }
198 return err
199}
200
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700201// See AccessProvider interface definition for details.
202func (a *Access) FirstEndpointUrlByCriteria(ac ApiCriteria) string {
203 ep := FindFirstEndpointByCriteria(a.ServiceCatalog, ac)
204 urls := []string{ep.PublicURL, ep.InternalURL}
205 return urls[ac.UrlChoice]
206}
Samuel A. Falvo IIbc0d54a2013-07-08 14:45:21 -0700207
208// See AccessProvider interface definition for details.
209func (a *Access) AuthToken() string {
210 return a.Token.Id
211}
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700212
213// See AccessProvider interface definition for details.
214func (a *Access) Revoke(tok string) error {
Samuel A. Falvo II0167aaa2013-07-16 12:36:25 -0700215 url := a.provider.AuthEndpoint + "/" + tok
216 err := perigee.Delete(url, perigee.Options{
217 MoreHeaders: map[string]string{
218 "X-Auth-Token": a.AuthToken(),
219 },
220 OkCodes: []int{204},
221 })
222 return err
Samuel A. Falvo II659e14b2013-07-16 12:04:54 -0700223}
Samuel A. Falvo IIcfb352a2013-11-19 14:39:37 -0800224
225// See ServiceCatalogerForIdentityV2 interface definition for details.
226// Note that the raw slice is returend; be careful not to alter the fields of any members,
227// for other components of Gophercloud may depend upon them.
228// If this becomes a problem in the future,
229// a future revision may return a deep-copy of the service catalog instead.
230func (a *Access) V2ServiceCatalog() []CatalogEntry {
231 return a.ServiceCatalog
232}