~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/gopkg.in/goose.v1/testservices/identityservice/v3userpass.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package identityservice
 
2
 
 
3
import (
 
4
        "encoding/json"
 
5
        "fmt"
 
6
        "io/ioutil"
 
7
        "net/http"
 
8
        "time"
 
9
 
 
10
        "gopkg.in/goose.v1/testservices/hook"
 
11
)
 
12
 
 
13
// V3UserPassRequest Implement the v3 User Pass form of identity (Keystone)
 
14
type V3UserPassRequest struct {
 
15
        Auth struct {
 
16
                Identity struct {
 
17
                        Methods  []string `json:"methods"`
 
18
                        Password struct {
 
19
                                User struct {
 
20
                                        Name     string `json:"name"`
 
21
                                        Password string `json:"password"`
 
22
                                } `json:"user"`
 
23
                        } `json:"password"`
 
24
                } `json:"identity"`
 
25
                Scope struct {
 
26
                        Project struct {
 
27
                                Name string `json:"name"`
 
28
                        } `json:"project"`
 
29
                } `json:"scope"`
 
30
        } `json:"auth"`
 
31
}
 
32
 
 
33
// V3Endpoint represents endpoints to a Service
 
34
type V3Endpoint struct {
 
35
        Interface string `json:"interface"`
 
36
        RegionID  string `json:"region_id"`
 
37
        URL       string `json:"url"`
 
38
}
 
39
 
 
40
// NewV3Endpoints returns an array of V3Endpoint for the given Region and the
 
41
// passed admin, internal and public URLs.
 
42
func NewV3Endpoints(adminURL, internalURL, publicURL, regionID string) []V3Endpoint {
 
43
        var eps []V3Endpoint
 
44
        if adminURL != "" {
 
45
                eps = append(eps, V3Endpoint{
 
46
                        RegionID:  regionID,
 
47
                        Interface: "admin",
 
48
                        URL:       adminURL,
 
49
                })
 
50
        }
 
51
        if internalURL != "" {
 
52
                eps = append(eps, V3Endpoint{
 
53
                        RegionID:  regionID,
 
54
                        Interface: "internal",
 
55
                        URL:       internalURL,
 
56
                })
 
57
        }
 
58
        if publicURL != "" {
 
59
                eps = append(eps, V3Endpoint{
 
60
                        RegionID:  regionID,
 
61
                        Interface: "public",
 
62
                        URL:       publicURL,
 
63
                })
 
64
        }
 
65
        return eps
 
66
 
 
67
}
 
68
 
 
69
// V3Service represents an OpenStack web service that you can access through a URL.
 
70
type V3Service struct {
 
71
        ID        string       `json:"id"`
 
72
        Name      string       `json:"name"`
 
73
        Type      string       `json:"type"`
 
74
        Endpoints []V3Endpoint `json:"endpoints"`
 
75
}
 
76
 
 
77
// V3TokenResponse repesent a Token returned as a response to authentication to
 
78
// keystone v3.
 
79
type V3TokenResponse struct {
 
80
        Expires time.Time   `json:"expires_at"`
 
81
        Issued  time.Time   `json:"issued_at"`
 
82
        Methods []string    `json:"methods"`
 
83
        Catalog []V3Service `json:"catalog,omitempty"`
 
84
        Project *V3Project  `json:"project,omitempty"`
 
85
        User    struct {
 
86
                ID   string `json:"id"`
 
87
                Name string `json:"name"`
 
88
        } `json:"user"`
 
89
}
 
90
 
 
91
// V3Project represent an openstack project, A project is the base unit of ownership.
 
92
// Resources are owned by a specific project. A project is owned by a specific domain.
 
93
type V3Project struct {
 
94
        ID string `json:"id,omitempty"`
 
95
}
 
96
 
 
97
// V3UserPass represents an authenticated user to a service.
 
98
type V3UserPass struct {
 
99
        hook.TestService
 
100
        Users
 
101
        services []V3Service
 
102
}
 
103
 
 
104
// NewV3UserPass returns a new V3UserPass
 
105
func NewV3UserPass() *V3UserPass {
 
106
        userpass := &V3UserPass{
 
107
                services: make([]V3Service, 0),
 
108
        }
 
109
        userpass.users = make(map[string]UserInfo)
 
110
        userpass.tenants = make(map[string]string)
 
111
        return userpass
 
112
}
 
113
 
 
114
// RegisterServiceProvider registers V3UserPass as a service provider.
 
115
func (u *V3UserPass) RegisterServiceProvider(name, serviceType string, serviceProvider ServiceProvider) {
 
116
        service := V3Service{
 
117
                ID:        name,
 
118
                Name:      name,
 
119
                Type:      serviceType,
 
120
                Endpoints: serviceProvider.V3Endpoints(),
 
121
        }
 
122
        u.AddService(Service{V3: service})
 
123
}
 
124
 
 
125
// AddService adds a service to the current V3UserPass.
 
126
func (u *V3UserPass) AddService(service Service) {
 
127
        u.services = append(u.services, service.V3)
 
128
}
 
129
 
 
130
// ReturnFailure wraps and returns an error through the http connection.
 
131
func (u *V3UserPass) ReturnFailure(w http.ResponseWriter, status int, message string) {
 
132
        e := ErrorWrapper{
 
133
                Error: ErrorResponse{
 
134
                        Message: message,
 
135
                        Code:    status,
 
136
                        Title:   http.StatusText(status),
 
137
                },
 
138
        }
 
139
        if content, err := json.Marshal(e); err != nil {
 
140
                w.Header().Set("Content-Length", fmt.Sprintf("%d", len(internalError)))
 
141
                w.WriteHeader(http.StatusInternalServerError)
 
142
                w.Write(internalError)
 
143
        } else {
 
144
                w.Header().Set("Content-Length", fmt.Sprintf("%d", len(content)))
 
145
                w.WriteHeader(status)
 
146
                w.Write(content)
 
147
        }
 
148
}
 
149
 
 
150
// ServeHTTP serves V3UserPass for testing purposes.
 
151
func (u *V3UserPass) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
152
        var req V3UserPassRequest
 
153
        // Testing against Canonistack, all responses are application/json, even failures
 
154
        w.Header().Set("Content-Type", "application/json")
 
155
        if r.Header.Get("Content-Type") != "application/json" {
 
156
                u.ReturnFailure(w, http.StatusBadRequest, notJSON)
 
157
                return
 
158
        }
 
159
        if content, err := ioutil.ReadAll(r.Body); err != nil {
 
160
                w.WriteHeader(http.StatusBadRequest)
 
161
                return
 
162
        } else {
 
163
                if err := json.Unmarshal(content, &req); err != nil {
 
164
                        u.ReturnFailure(w, http.StatusBadRequest, notJSON)
 
165
                        return
 
166
                }
 
167
        }
 
168
        userInfo, errmsg := u.authenticate(
 
169
                req.Auth.Identity.Password.User.Name,
 
170
                req.Auth.Identity.Password.User.Password,
 
171
        )
 
172
        if errmsg != "" {
 
173
                u.ReturnFailure(w, http.StatusUnauthorized, errmsg)
 
174
                return
 
175
        }
 
176
 
 
177
        res, err := u.generateV3TokenResponse(userInfo)
 
178
        if err != nil {
 
179
                u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
 
180
                return
 
181
        }
 
182
        if req.Auth.Scope.Project.Name != "" {
 
183
                res.Project = &V3Project{
 
184
                        ID: u.addTenant(req.Auth.Scope.Project.Name),
 
185
                }
 
186
        }
 
187
        content, err := json.Marshal(struct {
 
188
                Token *V3TokenResponse `json:"token"`
 
189
        }{
 
190
                Token: res,
 
191
        })
 
192
        if err != nil {
 
193
                u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
 
194
                return
 
195
        }
 
196
        w.Header().Set("X-Subject-Token", userInfo.Token)
 
197
        w.WriteHeader(http.StatusCreated)
 
198
        w.Write(content)
 
199
}
 
200
 
 
201
func (u *V3UserPass) generateV3TokenResponse(userInfo *UserInfo) (*V3TokenResponse, error) {
 
202
        res := V3TokenResponse{}
 
203
 
 
204
        res.Issued = time.Now()
 
205
        res.Expires = res.Issued.Add(24 * time.Hour)
 
206
        res.Methods = []string{"password"}
 
207
        res.Catalog = u.services
 
208
        res.User.ID = userInfo.Id
 
209
 
 
210
        return &res, nil
 
211
}
 
212
 
 
213
// SetupHTTP attaches all the needed handlers to provide the HTTP API.
 
214
func (u *V3UserPass) SetupHTTP(mux *http.ServeMux) {
 
215
        mux.Handle("/v3/auth/tokens", u)
 
216
}