blob: 9a7518f8f3f31e923e28d19c1d72a9cf80c2ea5c [file] [log] [blame]
Ash Wilson54b03822014-10-07 14:18:41 -04001package rackspace
2
3import (
Ash Wilson9e172e82014-10-07 16:42:39 -04004 "fmt"
Ash Wilson54b03822014-10-07 14:18:41 -04005
6 "github.com/rackspace/gophercloud"
7 os "github.com/rackspace/gophercloud/openstack"
Ash Wilson9e172e82014-10-07 16:42:39 -04008 "github.com/rackspace/gophercloud/openstack/utils"
9 tokens2 "github.com/rackspace/gophercloud/rackspace/identity/v2/tokens"
Ash Wilson54b03822014-10-07 14:18:41 -040010)
11
12const (
13 // RackspaceUSIdentity is an identity endpoint located in the United States.
14 RackspaceUSIdentity = "https://identity.api.rackspacecloud.com/v2.0/"
15
16 // RackspaceUKIdentity is an identity endpoint located in the UK.
17 RackspaceUKIdentity = "https://lon.identity.api.rackspacecloud.com/v2.0/"
18)
19
Ash Wilson9e172e82014-10-07 16:42:39 -040020const (
21 v20 = "v2.0"
22)
23
Ash Wilson54b03822014-10-07 14:18:41 -040024// NewClient creates a client that's prepared to communicate with the Rackspace API, but is not
25// yet authenticated. Most users will probably prefer using the AuthenticatedClient function
26// instead.
27//
28// Provide the base URL of the identity endpoint you wish to authenticate against as "endpoint".
29// Often, this will be either RackspaceUSIdentity or RackspaceUKIdentity.
30func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
31 return os.NewClient(endpoint)
32}
33
34// AuthenticatedClient logs in to Rackspace with the provided credentials and constructs a
35// ProviderClient that's ready to operate.
36//
37// If the provided AuthOptions does not specify an explicit IdentityEndpoint, it will default to
38// the canonical, production Rackspace US identity endpoint.
39func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
40 if options.IdentityEndpoint == "" {
41 options.IdentityEndpoint = RackspaceUSIdentity
42 }
43
Ash Wilson9e172e82014-10-07 16:42:39 -040044 client, err := NewClient(options.IdentityEndpoint)
Ash Wilson54b03822014-10-07 14:18:41 -040045 if err != nil {
46 return nil, err
47 }
48
Ash Wilson9e172e82014-10-07 16:42:39 -040049 err = Authenticate(client, options)
50 if err != nil {
51 return nil, err
52 }
53 return client, nil
54}
55
56// Authenticate or re-authenticate against the most recent identity service supported at the
57// provided endpoint.
58func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
59 versions := []*utils.Version{
60 &utils.Version{ID: v20, Priority: 20, Suffix: "/v2.0/"},
61 }
62
63 chosen, endpoint, err := utils.ChooseVersion(client.IdentityBase, client.IdentityEndpoint, versions)
64 if err != nil {
65 return err
66 }
67
68 switch chosen.ID {
69 case v20:
70 return v2auth(client, endpoint, options)
71 default:
72 // The switch statement must be out of date from the versions list.
73 return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
74 }
75}
76
77func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions) error {
78 v2Client := NewIdentityV2(client)
79 if endpoint != "" {
80 v2Client.Endpoint = endpoint
81 }
82
83 result := tokens2.Create(v2Client, tokens2.WrapOptions(options))
84
85 token, err := result.ExtractToken()
86 if err != nil {
87 return err
88 }
89
90 catalog, err := result.ExtractServiceCatalog()
91 if err != nil {
92 return err
93 }
94
95 client.TokenID = token.ID
96 client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
97 return os.V2EndpointURL(catalog, opts)
98 }
99
100 return nil
101}
102
103// NewIdentityV2 creates a ServiceClient that may be used to access the v2 identity service.
104func NewIdentityV2(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
105 v2Endpoint := client.IdentityBase + "v2.0/"
106
107 return &gophercloud.ServiceClient{
108 Provider: client,
109 Endpoint: v2Endpoint,
110 }
Ash Wilson54b03822014-10-07 14:18:41 -0400111}