gopkg.in/goose.v2@v2.0.1/testservices/identityservice/keypair.go (about) 1 package identityservice 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 9 "gopkg.in/goose.v2/testservices/hook" 10 ) 11 12 // Implement the v2 Key Pair form of identity based on Keystone 13 14 type KeyPairRequest struct { 15 Auth struct { 16 ApiAccessKeyCredentials struct { 17 AccessKey string `json:"accessKey"` 18 SecretKey string `json:"secretKey"` 19 } `json:"apiAccessKeyCredentials"` 20 TenantName string `json:"tenantName"` 21 } `json:"auth"` 22 } 23 24 type KeyPair struct { 25 hook.TestService 26 Users 27 services []V2Service 28 } 29 30 func NewKeyPair() *KeyPair { 31 return &KeyPair{ 32 Users: Users{ 33 users: make(map[string]UserInfo), 34 tenants: make(map[string]string), 35 }, 36 } 37 } 38 39 func (u *KeyPair) RegisterServiceProvider(name, serviceType string, serviceProvider ServiceProvider) { 40 service := V2Service{name, serviceType, serviceProvider.Endpoints()} 41 u.AddService(Service{V2: service}) 42 } 43 44 func (u *KeyPair) AddService(service Service) { 45 u.services = append(u.services, service.V2) 46 } 47 48 func (u *KeyPair) ReturnFailure(w http.ResponseWriter, status int, message string) { 49 e := ErrorWrapper{ 50 Error: ErrorResponse{ 51 Message: message, 52 Code: status, 53 Title: http.StatusText(status), 54 }, 55 } 56 if content, err := json.Marshal(e); err != nil { 57 w.Header().Set("Content-Length", fmt.Sprintf("%d", len(internalError))) 58 w.WriteHeader(http.StatusInternalServerError) 59 w.Write(internalError) 60 } else { 61 w.Header().Set("Content-Length", fmt.Sprintf("%d", len(content))) 62 w.WriteHeader(status) 63 w.Write(content) 64 } 65 } 66 67 func (u *KeyPair) ServeHTTP(w http.ResponseWriter, r *http.Request) { 68 var req KeyPairRequest 69 // Testing against Canonistack, all responses are application/json, even failures 70 w.Header().Set("Content-Type", "application/json") 71 if r.Header.Get("Content-Type") != "application/json" { 72 u.ReturnFailure(w, http.StatusBadRequest, notJSON) 73 return 74 } 75 if content, err := ioutil.ReadAll(r.Body); err != nil { 76 w.WriteHeader(http.StatusBadRequest) 77 return 78 } else { 79 if err := json.Unmarshal(content, &req); err != nil { 80 u.ReturnFailure(w, http.StatusBadRequest, notJSON) 81 return 82 } 83 } 84 userInfo, errmsg := u.authenticate(req.Auth.ApiAccessKeyCredentials.AccessKey, req.Auth.ApiAccessKeyCredentials.SecretKey, "default") 85 if errmsg != "" { 86 u.ReturnFailure(w, http.StatusUnauthorized, errmsg) 87 return 88 } 89 res, err := u.generateAccessResponse(userInfo) 90 if err != nil { 91 u.ReturnFailure(w, http.StatusInternalServerError, err.Error()) 92 return 93 } 94 content, err := json.Marshal(res) 95 if err != nil { 96 u.ReturnFailure(w, http.StatusInternalServerError, err.Error()) 97 return 98 } 99 w.WriteHeader(http.StatusOK) 100 w.Write(content) 101 } 102 103 func (u *KeyPair) generateAccessResponse(userInfo *UserInfo) (*AccessResponse, error) { 104 res := AccessResponse{} 105 // We pre-populate the response with genuine entries so that it looks sane. 106 if err := json.Unmarshal([]byte(exampleResponse), &res); err != nil { 107 return nil, err 108 } 109 res.Access.ServiceCatalog = u.services 110 res.Access.Token.Id = userInfo.Token 111 res.Access.Token.Tenant.Id = userInfo.TenantId 112 res.Access.User.Id = userInfo.Id 113 if err := u.ProcessControlHook("authorisation", u, &res, userInfo); err != nil { 114 return nil, err 115 } 116 return &res, nil 117 } 118 119 // setupHTTP attaches all the needed handlers to provide the HTTP API. 120 func (u *KeyPair) SetupHTTP(mux *http.ServeMux) { 121 mux.Handle("/tokens", u) 122 } 123 124 func (u *KeyPair) Stop() { 125 // noop 126 }