2 * Copyright 2018 Intel Corporation, Inc
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 "github.com/gorilla/mux"
24 uuid "github.com/hashicorp/go-uuid"
25 smsbackend "sms/backend"
29 // handler stores two interface implementations that implement
30 // the backend functionality
32 secretBackend smsbackend.SecretBackend
33 loginBackend smsbackend.LoginBackend
36 // createSecretDomainHandler creates a secret domain with a name provided
37 func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) {
38 var d smsbackend.SecretDomain
40 err := json.NewDecoder(r.Body).Decode(&d)
41 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
42 http.Error(w, err.Error(), http.StatusBadRequest)
46 dom, err := h.secretBackend.CreateSecretDomain(d.Name)
47 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
48 http.Error(w, err.Error(), http.StatusInternalServerError)
52 w.Header().Set("Content-Type", "application/json")
53 w.WriteHeader(http.StatusCreated)
54 err = json.NewEncoder(w).Encode(dom)
55 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
56 http.Error(w, err.Error(), http.StatusInternalServerError)
61 // deleteSecretDomainHandler deletes a secret domain with the name provided
62 func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) {
64 domName := vars["domName"]
66 err := h.secretBackend.DeleteSecretDomain(domName)
67 if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil {
68 http.Error(w, err.Error(), http.StatusInternalServerError)
72 w.WriteHeader(http.StatusNoContent)
75 // createSecretHandler handles creation of secrets on a given domain name
76 func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) {
77 // Get domain name from URL
79 domName := vars["domName"]
81 // Get secrets to be stored from body
82 var b smsbackend.Secret
83 err := json.NewDecoder(r.Body).Decode(&b)
84 if smslogger.CheckError(err, "CreateSecretHandler") != nil {
85 http.Error(w, err.Error(), http.StatusBadRequest)
89 err = h.secretBackend.CreateSecret(domName, b)
90 if smslogger.CheckError(err, "CreateSecretHandler") != nil {
91 http.Error(w, err.Error(), http.StatusInternalServerError)
95 w.WriteHeader(http.StatusCreated)
98 // getSecretHandler handles reading a secret by given domain name and secret name
99 func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) {
101 domName := vars["domName"]
102 secName := vars["secretName"]
104 sec, err := h.secretBackend.GetSecret(domName, secName)
105 if smslogger.CheckError(err, "GetSecretHandler") != nil {
106 http.Error(w, err.Error(), http.StatusInternalServerError)
110 w.Header().Set("Content-Type", "application/json")
111 err = json.NewEncoder(w).Encode(sec)
112 if smslogger.CheckError(err, "GetSecretHandler") != nil {
113 http.Error(w, err.Error(), http.StatusInternalServerError)
118 // listSecretHandler handles listing all secrets under a particular domain name
119 func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) {
121 domName := vars["domName"]
123 secList, err := h.secretBackend.ListSecret(domName)
124 if smslogger.CheckError(err, "ListSecretHandler") != nil {
125 http.Error(w, err.Error(), http.StatusInternalServerError)
129 // Creating an anonymous struct to store the returned list of data
130 var retStruct = struct {
131 SecretNames []string `json:"secretnames"`
136 w.Header().Set("Content-Type", "application/json")
137 err = json.NewEncoder(w).Encode(retStruct)
138 if smslogger.CheckError(err, "ListSecretHandler") != nil {
139 http.Error(w, err.Error(), http.StatusInternalServerError)
144 // deleteSecretHandler handles deleting a secret by given domain name and secret name
145 func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) {
147 domName := vars["domName"]
148 secName := vars["secretName"]
150 err := h.secretBackend.DeleteSecret(domName, secName)
151 if smslogger.CheckError(err, "DeleteSecretHandler") != nil {
152 http.Error(w, err.Error(), http.StatusInternalServerError)
156 w.WriteHeader(http.StatusNoContent)
159 // statusHandler returns information related to SMS and SMS backend services
160 func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) {
161 s, err := h.secretBackend.GetStatus()
162 if smslogger.CheckError(err, "StatusHandler") != nil {
163 http.Error(w, err.Error(), http.StatusInternalServerError)
168 Seal bool `json:"sealstatus"`
173 w.Header().Set("Content-Type", "application/json")
174 err = json.NewEncoder(w).Encode(status)
175 if smslogger.CheckError(err, "StatusHandler") != nil {
176 http.Error(w, err.Error(), http.StatusInternalServerError)
181 // loginHandler handles login via password and username
182 func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) {
186 // unsealHandler is a pass through that sends requests from quorum client
188 func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) {
189 // Get shards to be used for unseal
190 type unsealStruct struct {
191 UnsealShard string `json:"unsealshard"`
195 decoder := json.NewDecoder(r.Body)
196 decoder.DisallowUnknownFields()
197 err := decoder.Decode(&inp)
198 if smslogger.CheckError(err, "UnsealHandler") != nil {
199 http.Error(w, "Bad input JSON", http.StatusBadRequest)
203 err = h.secretBackend.Unseal(inp.UnsealShard)
204 if smslogger.CheckError(err, "UnsealHandler") != nil {
205 http.Error(w, err.Error(), http.StatusInternalServerError)
210 // registerHandler allows the quorum clients to register with SMS
211 // with their PGP public keys that are then used by sms for backend
213 func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) {
215 // Get shards to be used for unseal
216 type registerStruct struct {
217 PGPKey string `json:"pgpkey"`
218 QuorumID string `json:"quorumid"`
221 var inp registerStruct
222 decoder := json.NewDecoder(r.Body)
223 decoder.DisallowUnknownFields()
224 err := decoder.Decode(&inp)
225 if smslogger.CheckError(err, "RegisterHandler") != nil {
226 http.Error(w, "Bad input JSON", http.StatusBadRequest)
230 sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
231 if smslogger.CheckError(err, "RegisterHandler") != nil {
232 http.Error(w, err.Error(), http.StatusInternalServerError)
236 // Creating a struct for return data
238 Shard string `json:"shard"`
243 w.Header().Set("Content-Type", "application/json")
244 err = json.NewEncoder(w).Encode(shStruct)
245 if smslogger.CheckError(err, "RegisterHandler") != nil {
246 http.Error(w, err.Error(), http.StatusInternalServerError)
251 // healthCheckHandler runs a few commands on the backend and returns
252 // OK or not depending on the status of the backend
253 func (h handler) healthCheckHandler(w http.ResponseWriter, r *http.Request) {
255 sealed, err := h.secretBackend.GetStatus()
256 if smslogger.CheckError(err, "HealthCheck") != nil {
257 http.Error(w, err.Error(), http.StatusInternalServerError)
263 http.Error(w, "Secret Backend is not ready for operations", http.StatusInternalServerError)
267 // backend is not sealed
268 dname, _ := uuid.GenerateUUID()
269 _, err = h.secretBackend.CreateSecretDomain(dname)
270 if smslogger.CheckError(err, "HealthCheck Create Domain") != nil {
271 http.Error(w, err.Error(), http.StatusInternalServerError)
275 err = h.secretBackend.DeleteSecretDomain(dname)
276 if smslogger.CheckError(err, "HealthCheck Delete Domain") != nil {
277 http.Error(w, err.Error(), http.StatusInternalServerError)
281 w.WriteHeader(http.StatusOK)
284 // CreateRouter returns an http.Handler for the registered URLs
285 // Takes an interface implementation as input
286 func CreateRouter(b smsbackend.SecretBackend) http.Handler {
287 h := handler{secretBackend: b}
289 // Create a new mux to handle URL endpoints
290 router := mux.NewRouter()
292 router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST")
294 // Initialization APIs which will be used by quorum client
295 // to unseal and to provide root token to sms service
296 router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
297 router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
298 router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
300 router.HandleFunc("/v1/sms/healthcheck", h.healthCheckHandler).Methods("GET")
301 router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
302 router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
304 router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST")
305 router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET")
306 router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET")
307 router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE")