Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(132)

Side by Side Diff: testservices/identityservice/userpass.go

Issue 6844087: goose: all current code
Patch Set: Created 12 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 package identityservice
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io/ioutil"
7 "net/http"
8 )
9
10 // Implement the v2 User Pass form of identity (Keystone)
11
12 type ErrorResponse struct {
rog 2012/11/26 12:51:38 do all the below types need to be exported? it ma
13 Message string `json:"message"`
14 Code int `json:"code"`
15 Title string `json:"title"`
16 }
17
18 type ErrorWrapper struct {
19 Error ErrorResponse `json:"error"`
20 }
21
22 type UserPassRequest struct {
23 Auth struct {
24 PasswordCredentials struct {
25 Username string `json:"username"`
26 Password string `json:"password"`
27 } `json:"passwordCredentials"`
28 TenantName string `json:"tenantName"`
29 } `json:"auth"`
30 }
31
32 type Endpoint struct {
33 AdminURL string `json:"adminURL"`
34 InternalURL string `json:"internalURL"`
35 PublicURL string `json:"publicURL"`
36 Region string `json:"region"`
37 }
38
39 type Service struct {
40 Name string `json:"name"`
41 Type string `json:"type"`
42 Endpoints []Endpoint
43 }
44
45 type TokenResponse struct {
46 Expires string `json:"expires"` // should this be a date object?
47 Id string `json:"id"` // Actual token string
48 Tenant struct {
49 Id string `json:"id"`
50 Name string `json:"name"`
51 } `json:"tenant"`
52 }
53
54 type RoleResponse struct {
55 Id string `json:"id"`
56 Name string `json:"name"`
57 TenantId string `json:"tenantId"`
58 }
59
60 type UserResponse struct {
61 Id string `json:"id"`
62 Name string `json:"name"`
63 Roles []RoleResponse `json:"roles"`
64 }
65
66 type AccessResponse struct {
67 Access struct {
68 ServiceCatalog []Service `json:"serviceCatalog"`
69 Token TokenResponse `json:"token"`
70 User UserResponse `json:"user"`
71 } `json:"access"`
72 }
73
74 // Taken from: http://docs.openstack.org/api/quick-start/content/index.html#Gett ing-Credentials-a00665
75 var exampleResponse = `{
76 "access": {
77 "serviceCatalog": [
78 {
79 "endpoints": [
80 {
81 "adminURL": "https://nova-api.trystack.org:9774/v1.1/1",·······
82 "internalURL": "https://nova-api.trystack.org:9774/v1.1/ 1",·
83 "publicURL": "https://nova-api.trystack.org:9774/v1.1/1" ,·
84 "region": "RegionOne"
85 }
86 ],·
87 "name": "nova",·
88 "type": "compute"
89 },·
90 {
91 "endpoints": [
92 {
93 "adminURL": "https://GLANCE_API_IS_NOT_DISCLOSED/v1.1/1" ,·
94 "internalURL": "https://GLANCE_API_IS_NOT_DISCLOSED/v1.1 /1",·
95 "publicURL": "https://GLANCE_API_IS_NOT_DISCLOSED/v1.1/1 ",·
96 "region": "RegionOne"
97 }
98 ],·
99 "name": "glance",·
100 "type": "image"
101 },·
102 {
103 "endpoints": [
104 {
105 "adminURL": "https://nova-api.trystack.org:5443/v2.0",·
106 "internalURL": "https://keystone.trystack.org:5000/v2.0" ,·
107 "publicURL": "https://keystone.trystack.org:5000/v2.0",·
108 "region": "RegionOne"
109 }
110 ],·
111 "name": "keystone",·
112 "type": "identity"
113 }
114 ],·
115 "token": {
116 "expires": "2012-02-15T19:32:21",·
117 "id": "5df9d45d-d198-4222-9b4c-7a280aa35666",·
118 "tenant": {
119 "id": "1",·
120 "name": "admin"
121 }
122 },·
123 "user": {
124 "id": "14",·
125 "name": "annegentle",·
126 "roles": [
127 {
128 "id": "2",·
129 "name": "Member",·
130 "tenantId": "1"
131 }
132 ]
133 }
134 }
135 }`
136
137 type UserPass struct {
138 users map[string]UserInfo
139 services []Service
140 }
141
142 func NewUserPass() *UserPass {
143 userpass := &UserPass{
144 users: make(map[string]UserInfo),
145 services: make([]Service, 0),
146 }
147 return userpass
148 }
149
150 func (u *UserPass) AddUser(user, secret string) string {
151 token := randomHexToken()
152 u.users[user] = UserInfo{secret: secret, token: token}
153 return token
154 }
155
156 func (u *UserPass) AddService(service Service) {
157 u.services = append(u.services, service)
158 }
159
160 var internalError = []byte(`{
161 "error": {
162 "message": "Internal failure",
163 "code": 500,
164 "title": Internal Server Error"
165 }
166 }`)
167
168 func (u *UserPass) ReturnFailure(w http.ResponseWriter, status int, message stri ng) {
169 e := ErrorWrapper{
170 Error: ErrorResponse{
171 Message: message,
172 Code: status,
173 Title: http.StatusText(status),
174 },
175 }
176 if content, err := json.Marshal(e); err != nil {
177 w.Header().Set("Content-Length", fmt.Sprintf("%d", len(internalE rror)))
178 w.WriteHeader(http.StatusInternalServerError)
179 w.Write(internalError)
180 } else {
181 w.Header().Set("Content-Length", fmt.Sprintf("%d", len(content)) )
182 w.WriteHeader(status)
183 w.Write(content)
184 }
185 }
186
187 // Taken from an actual responses, however it may vary based on actual Openstack implementation
188 const (
189 notJSON = ("Expecting to find application/json in Content-Type header." +
190 " The server could not comply with the request since it is eithe r malformed" +
191 " or otherwise incorrect. The client is assumed to be in error." )
192 notAuthorized = "The request you have made requires authentication."
193 invalidUser = "Invalid user / password"
194 )
195
196 func (u *UserPass) ServeHTTP(w http.ResponseWriter, r *http.Request) {
197 var req UserPassRequest
198 // Testing against Canonistack, all responses are application/json, even failures
199 w.Header().Set("Content-Type", "application/json")
200 if r.Header.Get("Content-Type") != "application/json" {
201 u.ReturnFailure(w, http.StatusBadRequest, notJSON)
202 return
203 }
204 if content, err := ioutil.ReadAll(r.Body); err != nil {
205 w.WriteHeader(http.StatusBadRequest)
206 return
207 } else {
208 if err := json.Unmarshal(content, &req); err != nil {
209 u.ReturnFailure(w, http.StatusBadRequest, notJSON)
210 return
211 }
212 }
213 userInfo, ok := u.users[req.Auth.PasswordCredentials.Username]
214 if !ok {
215 u.ReturnFailure(w, http.StatusUnauthorized, notAuthorized)
216 return
217 }
218 if userInfo.secret != req.Auth.PasswordCredentials.Password {
219 u.ReturnFailure(w, http.StatusUnauthorized, invalidUser)
220 return
221 }
222 res := AccessResponse{}
223 // We pre-populate the response with genuine entries so that it looks sa ne.
224 // XXX: We should really build up valid state for this instead, at the
225 // very least, we should manage the URLs better.
226 if err := json.Unmarshal([]byte(exampleResponse), &res); err != nil {
227 u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
228 return
229 }
230 res.Access.ServiceCatalog = u.services
231 res.Access.Token.Id = userInfo.token
232 if content, err := json.Marshal(res); err != nil {
233 u.ReturnFailure(w, http.StatusInternalServerError, err.Error())
234 return
235 } else {
236 w.WriteHeader(http.StatusOK)
237 w.Write(content)
238 return
239 }
240 panic("All paths should have already returned")
241 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b