blob: e964d07cfde78c0aceb4fb85b13ccf7f740f4c16 [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 Wilson4dee1b82014-08-29 14:56:45 -04007
Ash Wilson8ba82242014-08-28 15:38:55 -04008 "github.com/rackspace/gophercloud"
Ash Wilsona87ee062014-09-03 11:26:06 -04009 tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
Ash Wilson4dee1b82014-08-29 14:56:45 -040010 "github.com/rackspace/gophercloud/openstack/utils"
Ash Wilson8ba82242014-08-28 15:38:55 -040011)
12
Ash Wilson4dee1b82014-08-29 14:56:45 -040013const (
14 v20 = "v2.0"
15 v30 = "v3.0"
16)
Ash Wilson8ba82242014-08-28 15:38:55 -040017
Ash Wilsona87ee062014-09-03 11:26:06 -040018// NewClient prepares an unauthenticated ProviderClient instance.
19// Most users will probably prefer using the AuthenticatedClient function instead.
20// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
21// for example.
22func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
23 // Normalize the identity endpoint that's provided by trimming any path, query or fragment from the URL.
24 u, err := url.Parse(endpoint)
25 if err != nil {
26 return nil, err
27 }
28 u.Path, u.RawQuery, u.Fragment = "", "", ""
29 normalized := u.String()
30
31 return &gophercloud.ProviderClient{
32 IdentityEndpoint: normalized,
33 Reauthenticate: func() error {
34 return errors.New("Unable to reauthenticate before authenticating the first time.")
35 },
36 }, nil
37}
38
39// 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 -040040// returns a Client instance that's ready to operate.
Ash Wilson8ba82242014-08-28 15:38:55 -040041// It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses
42// the most recent identity service available to proceed.
Ash Wilsona87ee062014-09-03 11:26:06 -040043func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
44 client, err := NewClient(options.IdentityEndpoint)
45 if err != nil {
46 return nil, err
47 }
48
49 err = Authenticate(client, options)
Ash Wilsonccd020b2014-09-02 10:40:54 -040050 if err != nil {
51 return nil, err
52 }
53 return client, nil
54}
55
Ash Wilsonccd020b2014-09-02 10:40:54 -040056// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint.
Ash Wilsona87ee062014-09-03 11:26:06 -040057func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
Ash Wilson4dee1b82014-08-29 14:56:45 -040058 versions := []*utils.Version{
59 &utils.Version{ID: v20, Priority: 20},
60 &utils.Version{ID: v30, Priority: 30},
61 }
62
Ash Wilsona87ee062014-09-03 11:26:06 -040063 chosen, endpoint, err := utils.ChooseVersion(client.IdentityEndpoint, versions)
Ash Wilson4dee1b82014-08-29 14:56:45 -040064 if err != nil {
Ash Wilsonccd020b2014-09-02 10:40:54 -040065 return err
Ash Wilson4dee1b82014-08-29 14:56:45 -040066 }
67
68 switch chosen.ID {
69 case v20:
Ash Wilsona87ee062014-09-03 11:26:06 -040070 return errors.New("Not implemented yet.")
Ash Wilson4dee1b82014-08-29 14:56:45 -040071 case v30:
Ash Wilsona87ee062014-09-03 11:26:06 -040072 // Override the generated service endpoint with the one returned by the version endpoint.
73 v3Client := NewIdentityV3(client)
74 v3Client.Endpoint = endpoint
75
76 result, err := tokens3.Create(v3Client, options, nil)
77 if err != nil {
78 return err
79 }
80
81 client.TokenID, err = result.TokenID()
82 if err != nil {
83 return err
84 }
85
86 return nil
Ash Wilson4dee1b82014-08-29 14:56:45 -040087 default:
Ash Wilsonccd020b2014-09-02 10:40:54 -040088 // The switch statement must be out of date from the versions list.
Ash Wilsona87ee062014-09-03 11:26:06 -040089 return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
Ash Wilsonccd020b2014-09-02 10:40:54 -040090 }
91}
92
Ash Wilsona87ee062014-09-03 11:26:06 -040093// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
94func NewIdentityV2(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
95 v2Endpoint := client.IdentityEndpoint + "/v2.0"
Ash Wilsonccd020b2014-09-02 10:40:54 -040096
Ash Wilsona87ee062014-09-03 11:26:06 -040097 return &gophercloud.ServiceClient{
98 Provider: client,
99 Endpoint: v2Endpoint,
Ash Wilson4dee1b82014-08-29 14:56:45 -0400100 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400101}
102
Ash Wilsona87ee062014-09-03 11:26:06 -0400103// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
104func NewIdentityV3(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
105 v3Endpoint := client.IdentityEndpoint + "/v3"
106
107 return &gophercloud.ServiceClient{
108 Provider: client,
109 Endpoint: v3Endpoint,
110 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400111}