blob: cbfde10056fa749f61f4386660ef6edbf05a7d8a [file] [log] [blame]
Ash Wilson8ba82242014-08-28 15:38:55 -04001package openstack
2
3import (
Ash Wilson4dee1b82014-08-29 14:56:45 -04004 "errors"
Ash Wilsona87ee062014-09-03 11:26:06 -04005 "fmt"
6 "net/url"
Ash Wilsoned6a1d82014-09-03 12:01:00 -04007 "strings"
Ash Wilson4dee1b82014-08-29 14:56:45 -04008
Ash Wilson8ba82242014-08-28 15:38:55 -04009 "github.com/rackspace/gophercloud"
Ash Wilsona87ee062014-09-03 11:26:06 -040010 tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
Ash Wilson4dee1b82014-08-29 14:56:45 -040011 "github.com/rackspace/gophercloud/openstack/utils"
Ash Wilson8ba82242014-08-28 15:38:55 -040012)
13
Ash Wilson4dee1b82014-08-29 14:56:45 -040014const (
15 v20 = "v2.0"
16 v30 = "v3.0"
17)
Ash Wilson8ba82242014-08-28 15:38:55 -040018
Ash Wilsona87ee062014-09-03 11:26:06 -040019// NewClient prepares an unauthenticated ProviderClient instance.
20// Most users will probably prefer using the AuthenticatedClient function instead.
21// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
22// for example.
23func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
24 // Normalize the identity endpoint that's provided by trimming any path, query or fragment from the URL.
25 u, err := url.Parse(endpoint)
26 if err != nil {
27 return nil, err
28 }
29 u.Path, u.RawQuery, u.Fragment = "", "", ""
30 normalized := u.String()
31
32 return &gophercloud.ProviderClient{
33 IdentityEndpoint: normalized,
34 Reauthenticate: func() error {
35 return errors.New("Unable to reauthenticate before authenticating the first time.")
36 },
37 }, nil
38}
39
40// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by options, acquires a token, and
Ash Wilsonccd020b2014-09-02 10:40:54 -040041// returns a Client instance that's ready to operate.
Ash Wilson8ba82242014-08-28 15:38:55 -040042// It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses
43// the most recent identity service available to proceed.
Ash Wilsona87ee062014-09-03 11:26:06 -040044func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
45 client, err := NewClient(options.IdentityEndpoint)
46 if err != nil {
47 return nil, err
48 }
49
50 err = Authenticate(client, options)
Ash Wilsonccd020b2014-09-02 10:40:54 -040051 if err != nil {
52 return nil, err
53 }
54 return client, nil
55}
56
Ash Wilsonccd020b2014-09-02 10:40:54 -040057// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint.
Ash Wilsona87ee062014-09-03 11:26:06 -040058func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
Ash Wilson4dee1b82014-08-29 14:56:45 -040059 versions := []*utils.Version{
60 &utils.Version{ID: v20, Priority: 20},
61 &utils.Version{ID: v30, Priority: 30},
62 }
63
Ash Wilsona87ee062014-09-03 11:26:06 -040064 chosen, endpoint, err := utils.ChooseVersion(client.IdentityEndpoint, versions)
Ash Wilson4dee1b82014-08-29 14:56:45 -040065 if err != nil {
Ash Wilsonccd020b2014-09-02 10:40:54 -040066 return err
Ash Wilson4dee1b82014-08-29 14:56:45 -040067 }
68
Ash Wilsoned6a1d82014-09-03 12:01:00 -040069 if !strings.HasSuffix(endpoint, "/") {
70 endpoint = endpoint + "/"
71 }
72
Ash Wilson4dee1b82014-08-29 14:56:45 -040073 switch chosen.ID {
74 case v20:
Ash Wilsona87ee062014-09-03 11:26:06 -040075 return errors.New("Not implemented yet.")
Ash Wilson4dee1b82014-08-29 14:56:45 -040076 case v30:
Ash Wilsona87ee062014-09-03 11:26:06 -040077 // Override the generated service endpoint with the one returned by the version endpoint.
78 v3Client := NewIdentityV3(client)
79 v3Client.Endpoint = endpoint
80
81 result, err := tokens3.Create(v3Client, options, nil)
82 if err != nil {
83 return err
84 }
85
86 client.TokenID, err = result.TokenID()
87 if err != nil {
88 return err
89 }
90
91 return nil
Ash Wilson4dee1b82014-08-29 14:56:45 -040092 default:
Ash Wilsonccd020b2014-09-02 10:40:54 -040093 // The switch statement must be out of date from the versions list.
Ash Wilsona87ee062014-09-03 11:26:06 -040094 return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
Ash Wilsonccd020b2014-09-02 10:40:54 -040095 }
96}
97
Ash Wilsona87ee062014-09-03 11:26:06 -040098// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
99func NewIdentityV2(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
Ash Wilsoned6a1d82014-09-03 12:01:00 -0400100 v2Endpoint := client.IdentityEndpoint + "/v2.0/"
Ash Wilsonccd020b2014-09-02 10:40:54 -0400101
Ash Wilsona87ee062014-09-03 11:26:06 -0400102 return &gophercloud.ServiceClient{
103 Provider: client,
104 Endpoint: v2Endpoint,
Ash Wilson4dee1b82014-08-29 14:56:45 -0400105 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400106}
107
Ash Wilsona87ee062014-09-03 11:26:06 -0400108// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
109func NewIdentityV3(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
Ash Wilsoned6a1d82014-09-03 12:01:00 -0400110 v3Endpoint := client.IdentityEndpoint + "/v3/"
Ash Wilsona87ee062014-09-03 11:26:06 -0400111
112 return &gophercloud.ServiceClient{
113 Provider: client,
114 Endpoint: v3Endpoint,
115 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400116}