0568671f369d4ee16f08709c7089b88f8464ff3d
[aaf/sms.git] / sms-service / src / sms / handler / handler.go
1 /*
2  * Copyright 2018 Intel Corporation, Inc
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package handler
18
19 import (
20         "encoding/json"
21         "github.com/gorilla/mux"
22         "net/http"
23
24         smsbackend "sms/backend"
25         smslogger "sms/log"
26 )
27
28 // handler stores two interface implementations that implement
29 // the backend functionality
30 type handler struct {
31         secretBackend smsbackend.SecretBackend
32         loginBackend  smsbackend.LoginBackend
33 }
34
35 // createSecretDomainHandler creates a secret domain with a name provided
36 func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) {
37         var d smsbackend.SecretDomain
38
39         err := json.NewDecoder(r.Body).Decode(&d)
40         if err != nil {
41                 smslogger.WriteError(err.Error())
42                 http.Error(w, err.Error(), http.StatusBadRequest)
43                 return
44         }
45
46         dom, err := h.secretBackend.CreateSecretDomain(d.Name)
47         if err != nil {
48                 smslogger.WriteError(err.Error())
49                 http.Error(w, err.Error(), http.StatusInternalServerError)
50                 return
51         }
52
53         w.Header().Set("Content-Type", "application/json")
54         w.WriteHeader(http.StatusCreated)
55         err = json.NewEncoder(w).Encode(dom)
56         if err != nil {
57                 smslogger.WriteError(err.Error())
58                 http.Error(w, err.Error(), http.StatusInternalServerError)
59                 return
60         }
61 }
62
63 // deleteSecretDomainHandler deletes a secret domain with the name provided
64 func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) {
65         vars := mux.Vars(r)
66         domName := vars["domName"]
67
68         err := h.secretBackend.DeleteSecretDomain(domName)
69         if err != nil {
70                 smslogger.WriteError(err.Error())
71                 http.Error(w, err.Error(), http.StatusInternalServerError)
72                 return
73         }
74
75         w.WriteHeader(http.StatusNoContent)
76 }
77
78 // createSecretHandler handles creation of secrets on a given domain name
79 func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) {
80         // Get domain name from URL
81         vars := mux.Vars(r)
82         domName := vars["domName"]
83
84         // Get secrets to be stored from body
85         var b smsbackend.Secret
86         err := json.NewDecoder(r.Body).Decode(&b)
87         if err != nil {
88                 smslogger.WriteError(err.Error())
89                 http.Error(w, err.Error(), http.StatusBadRequest)
90                 return
91         }
92
93         err = h.secretBackend.CreateSecret(domName, b)
94         if err != nil {
95                 smslogger.WriteError(err.Error())
96                 http.Error(w, err.Error(), http.StatusInternalServerError)
97                 return
98         }
99
100         w.WriteHeader(http.StatusCreated)
101 }
102
103 // getSecretHandler handles reading a secret by given domain name and secret name
104 func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) {
105         vars := mux.Vars(r)
106         domName := vars["domName"]
107         secName := vars["secretName"]
108
109         sec, err := h.secretBackend.GetSecret(domName, secName)
110         if err != nil {
111                 smslogger.WriteError(err.Error())
112                 http.Error(w, err.Error(), http.StatusInternalServerError)
113                 return
114         }
115
116         w.Header().Set("Content-Type", "application/json")
117         err = json.NewEncoder(w).Encode(sec)
118         if err != nil {
119                 smslogger.WriteError(err.Error())
120                 http.Error(w, err.Error(), http.StatusInternalServerError)
121                 return
122         }
123 }
124
125 // listSecretHandler handles listing all secrets under a particular domain name
126 func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) {
127         vars := mux.Vars(r)
128         domName := vars["domName"]
129
130         secList, err := h.secretBackend.ListSecret(domName)
131         if err != nil {
132                 smslogger.WriteError(err.Error())
133                 http.Error(w, err.Error(), http.StatusInternalServerError)
134                 return
135         }
136
137         // Creating an anonymous struct to store the returned list of data
138         var retStruct = struct {
139                 SecretNames []string `json:"secretnames"`
140         }{
141                 secList,
142         }
143
144         w.Header().Set("Content-Type", "application/json")
145         err = json.NewEncoder(w).Encode(retStruct)
146         if err != nil {
147                 smslogger.WriteError(err.Error())
148                 http.Error(w, err.Error(), http.StatusInternalServerError)
149                 return
150         }
151 }
152
153 // deleteSecretHandler handles deleting a secret by given domain name and secret name
154 func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) {
155         vars := mux.Vars(r)
156         domName := vars["domName"]
157         secName := vars["secretName"]
158
159         err := h.secretBackend.DeleteSecret(domName, secName)
160         if err != nil {
161                 smslogger.WriteError(err.Error())
162                 http.Error(w, err.Error(), http.StatusInternalServerError)
163                 return
164         }
165
166         w.WriteHeader(http.StatusNoContent)
167 }
168
169 // statusHandler returns information related to SMS and SMS backend services
170 func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) {
171         s, err := h.secretBackend.GetStatus()
172         if err != nil {
173                 smslogger.WriteError(err.Error())
174                 http.Error(w, err.Error(), http.StatusInternalServerError)
175                 return
176         }
177
178         status := struct {
179                 Seal bool `json:"sealstatus"`
180         }{
181                 s,
182         }
183
184         w.Header().Set("Content-Type", "application/json")
185         err = json.NewEncoder(w).Encode(status)
186         if err != nil {
187                 smslogger.WriteError(err.Error())
188                 http.Error(w, err.Error(), http.StatusInternalServerError)
189                 return
190         }
191 }
192
193 // loginHandler handles login via password and username
194 func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) {
195
196 }
197
198 // unsealHandler is a pass through that sends requests from quorum client
199 // to the backend.
200 func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) {
201         // Get shards to be used for unseal
202         type unsealStruct struct {
203                 UnsealShard string `json:"unsealshard"`
204         }
205
206         var inp unsealStruct
207         decoder := json.NewDecoder(r.Body)
208         decoder.DisallowUnknownFields()
209         err := decoder.Decode(&inp)
210         if err != nil {
211                 smslogger.WriteError(err.Error())
212                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
213                 return
214         }
215
216         err = h.secretBackend.Unseal(inp.UnsealShard)
217         if err != nil {
218                 smslogger.WriteError(err.Error())
219                 http.Error(w, err.Error(), http.StatusInternalServerError)
220                 return
221         }
222 }
223
224 // registerHandler allows the quorum clients to register with SMS
225 // with their PGP public keys that are then used by sms for backend
226 // initialization
227 func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) {
228         // Get shards to be used for unseal
229         type registerStruct struct {
230                 PGPKey   string `json:"pgpkey"`
231                 QuorumID string `json:"quorumid"`
232         }
233
234         smslogger.WriteInfo("Entering registerHandler")
235
236         var inp registerStruct
237         decoder := json.NewDecoder(r.Body)
238         decoder.DisallowUnknownFields()
239         err := decoder.Decode(&inp)
240         if err != nil {
241                 smslogger.WriteError(err.Error())
242                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
243                 return
244         }
245
246         sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
247         if err != nil {
248                 smslogger.WriteError(err.Error())
249                 http.Error(w, err.Error(), http.StatusInternalServerError)
250                 return
251         }
252
253         // Creating a struct for return data
254         shStruct := struct {
255                 Shard string `json:"shard"`
256         }{
257                 sh,
258         }
259
260         w.Header().Set("Content-Type", "application/json")
261         err = json.NewEncoder(w).Encode(shStruct)
262         if err != nil {
263                 smslogger.WriteError("Unable to encode response: " + err.Error())
264                 http.Error(w, err.Error(), http.StatusInternalServerError)
265                 return
266         }
267 }
268
269 // CreateRouter returns an http.Handler for the registered URLs
270 // Takes an interface implementation as input
271 func CreateRouter(b smsbackend.SecretBackend) http.Handler {
272         h := handler{secretBackend: b}
273
274         // Create a new mux to handle URL endpoints
275         router := mux.NewRouter()
276
277         router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST")
278
279         // Initialization APIs which will be used by quorum client
280         // to unseal and to provide root token to sms service
281         router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
282         router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
283         router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
284
285         router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
286         router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
287
288         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST")
289         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET")
290         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET")
291         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE")
292
293         return router
294 }