| package gophercloud |
| |
| import ( |
| "github.com/racker/perigee" |
| ) |
| |
| // 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. |
| type AuthOptions struct { |
| // Username and Password are required if using Identity V2 API. |
| // Consult with your provider's control panel to discover your |
| // account's username and password. |
| Username, Password string |
| |
| // The TenantId field is optional for the Identity V2 API. |
| TenantId 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 |
| } |
| |
| // 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 { |
| PasswordCredentials PasswordCredentials `json:"passwordCredentials"` |
| TenantId string `json:"tenantId,omitempty"` |
| } |
| |
| // PasswordCredentials provides a JSON encoding wrapper for passing credentials to the Identity |
| // service. You will not work with this structure directly. |
| type PasswordCredentials struct { |
| Username string `json:"username"` |
| Password string `json:"password"` |
| } |
| |
| // Access encapsulates the API token and its relevant fields, as well as the |
| // services catalog that Identity API returns once authenticated. |
| type Access struct { |
| Token Token |
| ServiceCatalog []CatalogEntry |
| User User |
| provider Provider `json:"-"` |
| options AuthOptions `json:"-"` |
| context *Context `json:"-"` |
| } |
| |
| // Token encapsulates an authentication token and when it expires. It also includes |
| // tenant information if available. |
| type Token struct { |
| Id, Expires string |
| Tenant Tenant |
| } |
| |
| // Tenant encapsulates tenant authentication information. If, after authentication, |
| // no tenant information is supplied, both Id and Name will be "". |
| type Tenant struct { |
| Id, Name string |
| } |
| |
| // User encapsulates the user credentials, and provides visibility in what |
| // the user can do through its role assignments. |
| type User struct { |
| Id, Name string |
| XRaxDefaultRegion string `json:"RAX-AUTH:defaultRegion"` |
| Roles []Role |
| } |
| |
| // Role encapsulates a permission that a user can rely on. |
| type Role struct { |
| Description, Id, Name string |
| } |
| |
| // CatalogEntry encapsulates a service catalog record. |
| type CatalogEntry struct { |
| Name, Type string |
| Endpoints []EntryEndpoint |
| } |
| |
| // EntryEndpoint encapsulates how to get to the API of some service. |
| type EntryEndpoint struct { |
| Region, TenantId string |
| PublicURL, InternalURL string |
| VersionId, VersionInfo, VersionList string |
| } |
| |
| // papersPlease contains the common logic between authentication and re-authentication. |
| // The name, obviously a joke on the process of authentication, was chosen because |
| // of how many other entities exist in the program containing the word Auth or Authorization. |
| // I didn't need another one. |
| func (c *Context) papersPlease(p Provider, options AuthOptions) (*Access, error) { |
| var access *Access |
| |
| if (options.Username == "") || (options.Password == "") { |
| return nil, ErrCredentials |
| } |
| |
| err := perigee.Post(p.AuthEndpoint, perigee.Options{ |
| CustomClient: c.httpClient, |
| ReqBody: &AuthContainer{ |
| Auth: Auth{ |
| PasswordCredentials: PasswordCredentials{ |
| Username: options.Username, |
| Password: options.Password, |
| }, |
| TenantId: options.TenantId, |
| }, |
| }, |
| Results: &struct { |
| Access **Access `json:"access"` |
| }{ |
| &access, |
| }, |
| }) |
| if err == nil { |
| access.options = options |
| access.provider = p |
| access.context = c |
| } |
| return access, err |
| } |
| |
| // Authenticate() grants access to the OpenStack-compatible provider API. |
| // |
| // Providers are identified through a unique key string. |
| // See the RegisterProvider() method for more details. |
| // |
| // The supplied AuthOptions instance allows the client to specify only those credentials |
| // relevant for the authentication request. At present, support exists for OpenStack |
| // Identity V2 API only; support for V3 will become available as soon as documentation for it |
| // becomes readily available. |
| // |
| // For Identity V2 API requirements, you must provide at least the Username and Password |
| // options. The TenantId field is optional, and defaults to "". |
| func (c *Context) Authenticate(provider string, options AuthOptions) (*Access, error) { |
| p, err := c.ProviderByName(provider) |
| if err != nil { |
| return nil, err |
| } |
| return c.papersPlease(p, options) |
| } |
| |
| // Reauthenticate attempts to reauthenticate using the configured access credentials, if |
| // allowed. This method takes no action unless your AuthOptions has the AllowReauth flag |
| // set to true. |
| func (a *Access) Reauthenticate() error { |
| var other *Access |
| var err error |
| |
| if a.options.AllowReauth { |
| other, err = a.context.papersPlease(a.provider, a.options) |
| if err == nil { |
| *a = *other |
| } |
| } |
| return err |
| } |
| |
| // See AccessProvider interface definition for details. |
| func (a *Access) FirstEndpointUrlByCriteria(ac ApiCriteria) string { |
| ep := FindFirstEndpointByCriteria(a.ServiceCatalog, ac) |
| urls := []string{ep.PublicURL, ep.InternalURL} |
| return urls[ac.UrlChoice] |
| } |
| |
| // See AccessProvider interface definition for details. |
| func (a *Access) AuthToken() string { |
| return a.Token.Id |
| } |
| |
| // See AccessProvider interface definition for details. |
| func (a *Access) Revoke(tok string) error { |
| url := a.provider.AuthEndpoint + "/" + tok |
| err := perigee.Delete(url, perigee.Options{ |
| MoreHeaders: map[string]string{ |
| "X-Auth-Token": a.AuthToken(), |
| }, |
| OkCodes: []int{204}, |
| }) |
| return err |
| } |