7ce9e01bbef472d916c1ea461adb395a285b944a
[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 smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
41                 http.Error(w, err.Error(), http.StatusBadRequest)
42                 return
43         }
44
45         dom, err := h.secretBackend.CreateSecretDomain(d.Name)
46         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
47                 http.Error(w, err.Error(), http.StatusInternalServerError)
48                 return
49         }
50
51         w.Header().Set("Content-Type", "application/json")
52         w.WriteHeader(http.StatusCreated)
53         err = json.NewEncoder(w).Encode(dom)
54         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
55                 http.Error(w, err.Error(), http.StatusInternalServerError)
56                 return
57         }
58 }
59
60 // deleteSecretDomainHandler deletes a secret domain with the name provided
61 func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) {
62         vars := mux.Vars(r)
63         domName := vars["domName"]
64
65         err := h.secretBackend.DeleteSecretDomain(domName)
66         if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil {
67                 http.Error(w, err.Error(), http.StatusInternalServerError)
68                 return
69         }
70
71         w.WriteHeader(http.StatusNoContent)
72 }
73
74 // createSecretHandler handles creation of secrets on a given domain name
75 func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) {
76         // Get domain name from URL
77         vars := mux.Vars(r)
78         domName := vars["domName"]
79
80         // Get secrets to be stored from body
81         var b smsbackend.Secret
82         err := json.NewDecoder(r.Body).Decode(&b)
83         if smslogger.CheckError(err, "CreateSecretHandler") != nil {
84                 http.Error(w, err.Error(), http.StatusBadRequest)
85                 return
86         }
87
88         err = h.secretBackend.CreateSecret(domName, b)
89         if smslogger.CheckError(err, "CreateSecretHandler") != nil {
90                 http.Error(w, err.Error(), http.StatusInternalServerError)
91                 return
92         }
93
94         w.WriteHeader(http.StatusCreated)
95 }
96
97 // getSecretHandler handles reading a secret by given domain name and secret name
98 func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) {
99         vars := mux.Vars(r)
100         domName := vars["domName"]
101         secName := vars["secretName"]
102
103         sec, err := h.secretBackend.GetSecret(domName, secName)
104         if smslogger.CheckError(err, "GetSecretHandler") != nil {
105                 http.Error(w, err.Error(), http.StatusInternalServerError)
106                 return
107         }
108
109         w.Header().Set("Content-Type", "application/json")
110         err = json.NewEncoder(w).Encode(sec)
111         if smslogger.CheckError(err, "GetSecretHandler") != nil {
112                 http.Error(w, err.Error(), http.StatusInternalServerError)
113                 return
114         }
115 }
116
117 // listSecretHandler handles listing all secrets under a particular domain name
118 func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) {
119         vars := mux.Vars(r)
120         domName := vars["domName"]
121
122         secList, err := h.secretBackend.ListSecret(domName)
123         if smslogger.CheckError(err, "ListSecretHandler") != nil {
124                 http.Error(w, err.Error(), http.StatusInternalServerError)
125                 return
126         }
127
128         // Creating an anonymous struct to store the returned list of data
129         var retStruct = struct {
130                 SecretNames []string `json:"secretnames"`
131         }{
132                 secList,
133         }
134
135         w.Header().Set("Content-Type", "application/json")
136         err = json.NewEncoder(w).Encode(retStruct)
137         if smslogger.CheckError(err, "ListSecretHandler") != nil {
138                 http.Error(w, err.Error(), http.StatusInternalServerError)
139                 return
140         }
141 }
142
143 // deleteSecretHandler handles deleting a secret by given domain name and secret name
144 func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) {
145         vars := mux.Vars(r)
146         domName := vars["domName"]
147         secName := vars["secretName"]
148
149         err := h.secretBackend.DeleteSecret(domName, secName)
150         if smslogger.CheckError(err, "DeleteSecretHandler") != nil {
151                 http.Error(w, err.Error(), http.StatusInternalServerError)
152                 return
153         }
154
155         w.WriteHeader(http.StatusNoContent)
156 }
157
158 // statusHandler returns information related to SMS and SMS backend services
159 func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) {
160         s, err := h.secretBackend.GetStatus()
161         if smslogger.CheckError(err, "StatusHandler") != nil {
162                 http.Error(w, err.Error(), http.StatusInternalServerError)
163                 return
164         }
165
166         status := struct {
167                 Seal bool `json:"sealstatus"`
168         }{
169                 s,
170         }
171
172         w.Header().Set("Content-Type", "application/json")
173         err = json.NewEncoder(w).Encode(status)
174         if smslogger.CheckError(err, "StatusHandler") != nil {
175                 http.Error(w, err.Error(), http.StatusInternalServerError)
176                 return
177         }
178 }
179
180 // loginHandler handles login via password and username
181 func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) {
182
183 }
184
185 // unsealHandler is a pass through that sends requests from quorum client
186 // to the backend.
187 func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) {
188         // Get shards to be used for unseal
189         type unsealStruct struct {
190                 UnsealShard string `json:"unsealshard"`
191         }
192
193         var inp unsealStruct
194         decoder := json.NewDecoder(r.Body)
195         decoder.DisallowUnknownFields()
196         err := decoder.Decode(&inp)
197         if smslogger.CheckError(err, "UnsealHandler") != nil {
198                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
199                 return
200         }
201
202         err = h.secretBackend.Unseal(inp.UnsealShard)
203         if smslogger.CheckError(err, "UnsealHandler") != nil {
204                 http.Error(w, err.Error(), http.StatusInternalServerError)
205                 return
206         }
207 }
208
209 // registerHandler allows the quorum clients to register with SMS
210 // with their PGP public keys that are then used by sms for backend
211 // initialization
212 func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) {
213         // Get shards to be used for unseal
214         type registerStruct struct {
215                 PGPKey   string `json:"pgpkey"`
216                 QuorumID string `json:"quorumid"`
217         }
218
219         var inp registerStruct
220         decoder := json.NewDecoder(r.Body)
221         decoder.DisallowUnknownFields()
222         err := decoder.Decode(&inp)
223         if smslogger.CheckError(err, "RegisterHandler") != nil {
224                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
225                 return
226         }
227
228         sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
229         if smslogger.CheckError(err, "RegisterHandler") != nil {
230                 http.Error(w, err.Error(), http.StatusInternalServerError)
231                 return
232         }
233
234         // Creating a struct for return data
235         shStruct := struct {
236                 Shard string `json:"shard"`
237         }{
238                 sh,
239         }
240
241         w.Header().Set("Content-Type", "application/json")
242         err = json.NewEncoder(w).Encode(shStruct)
243         if smslogger.CheckError(err, "RegisterHandler") != nil {
244                 http.Error(w, err.Error(), http.StatusInternalServerError)
245                 return
246         }
247 }
248
249 // CreateRouter returns an http.Handler for the registered URLs
250 // Takes an interface implementation as input
251 func CreateRouter(b smsbackend.SecretBackend) http.Handler {
252         h := handler{secretBackend: b}
253
254         // Create a new mux to handle URL endpoints
255         router := mux.NewRouter()
256
257         router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST")
258
259         // Initialization APIs which will be used by quorum client
260         // to unseal and to provide root token to sms service
261         router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
262         router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
263         router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
264
265         router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
266         router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
267
268         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST")
269         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET")
270         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET")
271         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE")
272
273         return router
274 }