2015-10-31 18:56:49 +00:00
|
|
|
/*
|
|
|
|
Copyright 2015 Gravitational, Inc.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
2015-03-02 20:11:23 +00:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2015-05-12 00:04:22 +00:00
|
|
|
"io/ioutil"
|
2015-03-02 20:11:23 +00:00
|
|
|
"net/http"
|
2015-07-11 00:24:44 +00:00
|
|
|
"strconv"
|
2015-03-02 20:11:23 +00:00
|
|
|
"time"
|
|
|
|
|
2015-08-25 17:54:16 +00:00
|
|
|
"github.com/gravitational/teleport"
|
2015-10-05 14:33:25 +00:00
|
|
|
"github.com/gravitational/teleport/lib/backend"
|
|
|
|
"github.com/gravitational/teleport/lib/backend/encryptedbk/encryptor"
|
|
|
|
"github.com/gravitational/teleport/lib/events"
|
|
|
|
"github.com/gravitational/teleport/lib/recorder"
|
2015-10-05 17:36:55 +00:00
|
|
|
"github.com/gravitational/teleport/lib/services"
|
2015-10-05 14:33:25 +00:00
|
|
|
"github.com/gravitational/teleport/lib/session"
|
2015-07-09 03:57:34 +00:00
|
|
|
|
2016-01-20 15:52:25 +00:00
|
|
|
"github.com/codahale/lunk"
|
|
|
|
"github.com/gravitational/form"
|
|
|
|
"github.com/gravitational/log"
|
|
|
|
"github.com/gravitational/roundtrip"
|
|
|
|
websession "github.com/gravitational/session"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
2015-03-02 20:11:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
Backend backend.Backend
|
|
|
|
Addr string
|
|
|
|
}
|
|
|
|
|
|
|
|
// APISrv implements http API server for authority
|
|
|
|
type APIServer struct {
|
|
|
|
httprouter.Router
|
2015-11-11 22:21:11 +00:00
|
|
|
a *AuthWithRoles
|
2015-05-12 00:04:22 +00:00
|
|
|
s *AuthServer
|
2015-07-09 03:57:34 +00:00
|
|
|
elog events.Log
|
2015-06-30 23:12:18 +00:00
|
|
|
se session.SessionServer
|
2015-07-11 00:24:44 +00:00
|
|
|
rec recorder.Recorder
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
func NewAPIServer(a *AuthWithRoles) *APIServer {
|
2015-03-02 20:11:23 +00:00
|
|
|
srv := &APIServer{
|
2015-11-11 22:21:11 +00:00
|
|
|
a: a,
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
srv.Router = *httprouter.New()
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
// Auth is for operations involving Certificate Authority
|
|
|
|
srv.POST("/v1/ca/host/keys", srv.resetHostCertificateAuthority)
|
|
|
|
srv.POST("/v1/ca/user/keys", srv.resetUserCertificateAuthority)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
|
|
|
// Retrieving authority public keys
|
2015-11-20 21:15:48 +00:00
|
|
|
srv.GET("/v1/ca/host/keys/pub", srv.getHostCertificateAuthority)
|
|
|
|
srv.GET("/v1/ca/user/keys/pub", srv.getUserCertificateAuthority)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
|
|
|
// Generating certificates for user and host authorities
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.POST("/v1/ca/host/certs", srv.generateHostCert)
|
|
|
|
srv.POST("/v1/ca/user/certs", srv.generateUserCert)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
|
|
|
// Operations on users
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.GET("/v1/users", srv.getUsers)
|
|
|
|
srv.DELETE("/v1/users/:user", srv.deleteUser)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
|
|
|
// Operations on user keys
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.POST("/v1/users/:user/keys", srv.upsertUserKey)
|
|
|
|
srv.DELETE("/v1/users/:user/keys/:key", srv.deleteUserKey)
|
|
|
|
srv.GET("/v1/users/:user/keys", srv.getUserKeys)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
|
|
|
// Generating keypairs
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.POST("/v1/keypair", srv.generateKeyPair)
|
|
|
|
|
2015-06-22 21:05:15 +00:00
|
|
|
// Operations on remote authorities we trust
|
2015-11-20 21:15:48 +00:00
|
|
|
srv.POST("/v1/ca/remote/:type/hosts/:domain", srv.upsertRemoteCertificate)
|
|
|
|
srv.DELETE("/v1/ca/remote/:type/hosts/:domain/:id", srv.deleteRemoteCertificate)
|
2015-11-18 04:39:19 +00:00
|
|
|
srv.GET("/v1/ca/remote/:type", srv.getRemoteCertificates)
|
|
|
|
|
|
|
|
srv.GET("/v1/ca/trusted/:type", srv.getTrustedCertificates)
|
2015-06-22 21:05:15 +00:00
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
// Passwords and sessions
|
|
|
|
srv.POST("/v1/users/:user/web/password", srv.upsertPassword)
|
|
|
|
srv.POST("/v1/users/:user/web/password/check", srv.checkPassword)
|
|
|
|
srv.POST("/v1/users/:user/web/signin", srv.signIn)
|
|
|
|
srv.GET("/v1/users/:user/web/sessions/:sid", srv.getWebSession)
|
2015-05-07 03:10:44 +00:00
|
|
|
srv.GET("/v1/users/:user/web/sessions", srv.getWebSessions)
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.DELETE("/v1/users/:user/web/sessions/:sid", srv.deleteWebSession)
|
2016-01-21 00:05:23 +00:00
|
|
|
srv.GET("/v1/users/adduser/token", srv.getAddUserTokenData)
|
|
|
|
srv.POST("/v1/users/adduser", srv.createUserWithToken)
|
2015-03-19 04:13:56 +00:00
|
|
|
|
|
|
|
// Web tunnels
|
|
|
|
srv.POST("/v1/tunnels/web", srv.upsertWebTun)
|
|
|
|
srv.GET("/v1/tunnels/web", srv.getWebTuns)
|
|
|
|
srv.GET("/v1/tunnels/web/:prefix", srv.getWebTun)
|
|
|
|
srv.DELETE("/v1/tunnels/web/:prefix", srv.deleteWebTun)
|
|
|
|
|
2015-07-11 00:24:44 +00:00
|
|
|
// Servers and presence heartbeat
|
2015-03-19 04:13:56 +00:00
|
|
|
srv.POST("/v1/servers", srv.upsertServer)
|
|
|
|
srv.GET("/v1/servers", srv.getServers)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
2015-05-07 03:10:44 +00:00
|
|
|
// Tokens
|
|
|
|
srv.POST("/v1/tokens", srv.generateToken)
|
2015-11-13 01:32:45 +00:00
|
|
|
srv.POST("/v1/tokens/register", srv.registerUsingToken)
|
|
|
|
srv.POST("/v1/tokens/register/auth", srv.registerNewAuthServer)
|
2015-05-12 00:04:22 +00:00
|
|
|
// Events
|
|
|
|
srv.POST("/v1/events", srv.submitEvents)
|
|
|
|
srv.GET("/v1/events", srv.getEvents)
|
|
|
|
|
2015-07-11 00:24:44 +00:00
|
|
|
// Recorded sessions
|
|
|
|
srv.POST("/v1/records/:sid/chunks", srv.submitChunks)
|
|
|
|
srv.GET("/v1/records/:sid/chunks", srv.getChunks)
|
|
|
|
|
2015-06-30 23:12:18 +00:00
|
|
|
// Sesssions
|
|
|
|
srv.POST("/v1/sessions/:id/parties", srv.upsertSessionParty)
|
2015-07-03 20:08:26 +00:00
|
|
|
srv.POST("/v1/sessions", srv.upsertSession)
|
2015-06-30 23:12:18 +00:00
|
|
|
srv.GET("/v1/sessions", srv.getSessions)
|
|
|
|
srv.GET("/v1/sessions/:id", srv.getSession)
|
|
|
|
srv.DELETE("/v1/sessions/:id", srv.deleteSession)
|
|
|
|
|
2015-09-12 01:19:20 +00:00
|
|
|
// Backend Keys
|
2015-09-28 22:04:10 +00:00
|
|
|
srv.GET("/v1/backend/keys", srv.getSealKeys)
|
|
|
|
srv.GET("/v1/backend/keys/:id", srv.getSealKey)
|
|
|
|
srv.DELETE("/v1/backend/keys/:id", srv.deleteSealKey)
|
|
|
|
srv.POST("/v1/backend/keys", srv.addSealKey)
|
|
|
|
srv.POST("/v1/backend/generatekey", srv.generateSealKey)
|
2015-09-12 01:19:20 +00:00
|
|
|
|
2015-03-02 20:11:23 +00:00
|
|
|
return srv
|
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
func (s *APIServer) getSealKeys(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
keys, err := s.a.GetSealKeys()
|
2015-09-12 01:19:20 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
2015-09-28 22:04:10 +00:00
|
|
|
reply(w, http.StatusOK, sealKeysResponse{Keys: keys})
|
2015-09-12 01:19:20 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
func (s *APIServer) getSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-09-12 01:19:20 +00:00
|
|
|
id := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
key, err := s.a.GetSealKey(id)
|
2015-09-12 01:19:20 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
2015-09-28 22:04:10 +00:00
|
|
|
reply(w, http.StatusOK, sealKeyResponse{Key: key})
|
2015-09-12 01:19:20 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
func (s *APIServer) deleteSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-09-12 01:19:20 +00:00
|
|
|
id := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
err := s.a.DeleteSealKey(id)
|
2015-09-12 01:19:20 +00:00
|
|
|
if err != nil {
|
2015-10-21 18:45:10 +00:00
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
2015-09-12 01:19:20 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message("Key "+id+" was deleted"))
|
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
func (s *APIServer) addSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var keyJSON string
|
2015-09-12 01:19:20 +00:00
|
|
|
err := form.Parse(r,
|
2015-10-21 18:45:10 +00:00
|
|
|
form.String("key", &keyJSON, form.Required()),
|
2015-09-12 01:19:20 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
var key encryptor.Key
|
|
|
|
if err := json.Unmarshal([]byte(keyJSON), &key); err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
err = s.a.AddSealKey(key)
|
2015-09-12 01:19:20 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
2015-09-28 22:04:10 +00:00
|
|
|
reply(w, http.StatusOK, message("ok"))
|
2015-09-12 01:19:20 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
func (s *APIServer) generateSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var name string
|
2015-09-12 01:19:20 +00:00
|
|
|
err := form.Parse(r,
|
2015-09-28 22:04:10 +00:00
|
|
|
form.String("name", &name, form.Required()),
|
2015-09-12 01:19:20 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
key, err := s.a.GenerateSealKey(name)
|
2015-09-12 01:19:20 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
2015-09-28 22:04:10 +00:00
|
|
|
reply(w, http.StatusOK, sealKeyResponse{Key: key})
|
2015-09-12 01:19:20 +00:00
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) upsertServer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-12-07 20:05:54 +00:00
|
|
|
var args upsertServerArgs
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-12-07 20:05:54 +00:00
|
|
|
|
|
|
|
if err := s.a.UpsertServer(args.Server, args.TTL); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message("server upserted"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getServers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
servers, err := s.a.GetServers()
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, serversResponse{Servers: servers})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) upsertWebTun(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var prefix, targetAddr, proxyAddr string
|
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("prefix", &prefix, form.Required()),
|
|
|
|
form.String("target", &targetAddr, form.Required()),
|
|
|
|
form.String("proxy", &proxyAddr, form.Required()),
|
|
|
|
form.Duration("ttl", &ttl),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-08-25 17:54:16 +00:00
|
|
|
t, err := services.NewWebTun(prefix, proxyAddr, targetAddr)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.UpsertWebTun(*t, ttl); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &webTunResponse{Tunnel: *t})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) deleteWebTun(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
prefix := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
err := s.a.DeleteWebTun(prefix)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("web tunnel '%v' deleted", prefix)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getWebTun(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
prefix := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
wt, err := s.a.GetWebTun(prefix)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &webTunResponse{Tunnel: *wt})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getWebTuns(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
ws, err := s.a.GetWebTuns()
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &webTunsResponse{Tunnels: ws})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) deleteWebSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
user, sid := p[0].Value, p[1].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
err := s.a.DeleteWebSession(user, websession.SecureID(sid))
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("session '%v' for user '%v' deleted", sid, user)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getWebSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
user, sid := p[0].Value, p[1].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
ws, err := s.a.GetWebSession(user, websession.SecureID(sid))
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-06-30 23:12:18 +00:00
|
|
|
reply(w, http.StatusOK, &webSessionResponse{SID: string(ws.SID)})
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
2015-05-07 03:10:44 +00:00
|
|
|
func (s *APIServer) getWebSessions(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
user := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
keys, err := s.a.GetWebSessionsKeys(user)
|
2015-05-07 03:10:44 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-06-30 23:12:18 +00:00
|
|
|
reply(w, http.StatusOK, &webSessionsResponse{Keys: keys})
|
2015-05-07 03:10:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) signIn(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-10-23 20:34:09 +00:00
|
|
|
var pass string
|
2015-03-19 04:13:56 +00:00
|
|
|
|
|
|
|
err := form.Parse(r,
|
2015-10-23 00:45:51 +00:00
|
|
|
form.String("password", &pass, form.Required()),
|
|
|
|
)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
user := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
ws, err := s.a.SignIn(user, []byte(pass))
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-06-30 23:12:18 +00:00
|
|
|
reply(w, http.StatusOK, &webSessionResponse{SID: string(ws.SID)})
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) upsertPassword(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var pass string
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("password", &pass, form.Required()))
|
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
user := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
hotpURL, hotpQR, err := s.a.UpsertPassword(user, []byte(pass))
|
2015-10-23 00:45:51 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-10-23 00:45:51 +00:00
|
|
|
reply(w, http.StatusOK,
|
|
|
|
&upsertPasswordResponse{HotpURL: hotpURL, HotpQR: hotpQR})
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) checkPassword(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var pass string
|
2015-10-23 00:45:51 +00:00
|
|
|
var hotpToken string
|
2015-03-19 04:13:56 +00:00
|
|
|
|
|
|
|
err := form.Parse(r,
|
2015-10-23 00:45:51 +00:00
|
|
|
form.String("password", &pass, form.Required()),
|
|
|
|
form.String("hotpToken", &hotpToken, form.Required()),
|
|
|
|
)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
user := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.CheckPassword(user, []byte(pass), hotpToken); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("'%v' user password matches", user)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) upsertUserKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
var id, key string
|
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("key", &key, form.Required()),
|
|
|
|
form.String("id", &id, form.Required()),
|
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
cert, err := s.a.UpsertUserKey(p[0].Value, services.AuthorizedKey{ID: id, Value: []byte(key)}, ttl)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, certResponse{Cert: string(cert)})
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) getUsers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
users, err := s.a.GetUsers()
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &usersResponse{Users: users})
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) deleteUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
user := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.DeleteUser(user); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("user '%v' deleted", user)))
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) getUserKeys(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
keys, err := s.a.GetUserKeys(p[0].Value)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, &pubKeysResponse{PubKeys: keys})
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) deleteUserKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
user, keyID := p[0].Value, p[1].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.DeleteUserKey(user, keyID); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("key '%v' deleted for user '%v'", keyID, user)))
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) generateKeyPair(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
var pass string
|
|
|
|
|
|
|
|
if err := form.Parse(r, form.String("pass", &pass)); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
priv, pub, err := s.a.GenerateKeyPair(pass)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, &keyPairResponse{PrivKey: priv, PubKey: string(pub)})
|
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
func (s *APIServer) resetHostCertificateAuthority(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
var pass string
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
err := form.Parse(r, form.String("pass", &pass))
|
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
2015-11-18 04:39:19 +00:00
|
|
|
|
|
|
|
if err := s.a.ResetHostCertificateAuthority(pass); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
2015-11-18 04:39:19 +00:00
|
|
|
reply(w, http.StatusOK, message("host Certificate Authority regenerated"))
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
func (s *APIServer) resetUserCertificateAuthority(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
var pass string
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
err := form.Parse(r, form.String("pass", &pass))
|
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
if err := s.a.ResetUserCertificateAuthority(pass); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
reply(w, http.StatusOK, message("user Certificate Authority regenerated"))
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
func (s *APIServer) getHostCertificateAuthority(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
cert, err := s.a.GetHostCertificateAuthority()
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
reply(w, http.StatusOK, *cert)
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
func (s *APIServer) getUserCertificateAuthority(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
cert, err := s.a.GetUserCertificateAuthority()
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
replyErr(w, err)
|
2015-03-02 20:11:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
reply(w, http.StatusOK, *cert)
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) generateHostCert(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-11-13 01:32:45 +00:00
|
|
|
var id, hostname, key, role string
|
2015-03-02 20:11:23 +00:00
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("key", &key, form.Required()),
|
|
|
|
form.String("id", &id, form.Required()),
|
|
|
|
form.String("hostname", &hostname, form.Required()),
|
2015-11-13 01:32:45 +00:00
|
|
|
form.String("role", &role, form.Required()),
|
2015-03-02 20:11:23 +00:00
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 01:32:45 +00:00
|
|
|
cert, err := s.a.GenerateHostCert([]byte(key), id, hostname, role, ttl)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, certResponse{Cert: string(cert)})
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *APIServer) generateUserCert(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-03-02 20:11:23 +00:00
|
|
|
var id, user, key string
|
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("key", &key, form.Required()),
|
|
|
|
form.String("id", &id, form.Required()),
|
|
|
|
form.String("user", &user, form.Required()),
|
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
cert, err := s.a.GenerateUserCert([]byte(key), id, user, ttl)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, certResponse{Cert: string(cert)})
|
|
|
|
}
|
|
|
|
|
2015-05-07 03:10:44 +00:00
|
|
|
func (s *APIServer) generateToken(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-11-20 21:15:48 +00:00
|
|
|
var domainName, role string
|
2015-05-07 03:10:44 +00:00
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
2015-11-20 21:15:48 +00:00
|
|
|
form.String("domain", &domainName, form.Required()),
|
2015-11-13 01:32:45 +00:00
|
|
|
form.String("role", &role, form.Required()),
|
2015-05-07 03:10:44 +00:00
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-05-07 03:10:44 +00:00
|
|
|
}
|
2015-11-20 21:15:48 +00:00
|
|
|
token, err := s.a.GenerateToken(domainName, role, ttl)
|
2015-05-07 03:10:44 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, tokenResponse{Token: string(token)})
|
|
|
|
}
|
|
|
|
|
2015-11-13 01:32:45 +00:00
|
|
|
func (s *APIServer) registerUsingToken(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-11-20 21:15:48 +00:00
|
|
|
var token, domainName, role string
|
2015-11-13 01:32:45 +00:00
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("token", &token, form.Required()),
|
2015-11-20 21:15:48 +00:00
|
|
|
form.String("domain", &domainName, form.Required()),
|
2015-11-13 01:32:45 +00:00
|
|
|
form.String("role", &role, form.Required()),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-11-13 01:32:45 +00:00
|
|
|
}
|
2015-11-20 21:15:48 +00:00
|
|
|
keys, err := s.a.RegisterUsingToken(token, domainName, role)
|
2015-11-13 01:32:45 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, keys)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) registerNewAuthServer(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-11-20 21:15:48 +00:00
|
|
|
var token, domainName, pkeyJSON string
|
2015-11-13 01:32:45 +00:00
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("token", &token, form.Required()),
|
2015-11-20 21:15:48 +00:00
|
|
|
form.String("domain", &domainName, form.Required()),
|
2015-11-13 01:32:45 +00:00
|
|
|
form.String("key", &pkeyJSON, form.Required()),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-11-13 01:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var pkey encryptor.Key
|
|
|
|
err = json.Unmarshal([]byte(pkeyJSON), &pkey)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-11-13 01:32:45 +00:00
|
|
|
}
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
key, err := s.a.RegisterNewAuthServer(domainName, token, pkey)
|
2015-11-13 01:32:45 +00:00
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, key)
|
|
|
|
}
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
func (s *APIServer) submitEvents(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
var events form.Files
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.FileSlice("event", &events))
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-05-12 00:04:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(events) == 0 {
|
|
|
|
reply(w, http.StatusBadRequest,
|
|
|
|
fmt.Errorf("at least one event is required"))
|
2015-11-16 05:21:34 +00:00
|
|
|
return
|
2015-05-12 00:04:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
// don't let get the error get lost
|
|
|
|
if err := events.Close(); err != nil {
|
|
|
|
log.Errorf("failed to close files: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// submit events
|
|
|
|
for _, e := range events {
|
|
|
|
data, err := ioutil.ReadAll(e)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to read event: %v", err)
|
|
|
|
reply(w, http.StatusBadRequest, fmt.Errorf("failed to read event"))
|
|
|
|
return
|
|
|
|
}
|
2015-07-09 03:57:34 +00:00
|
|
|
var e *lunk.Entry
|
|
|
|
if err := json.Unmarshal(data, &e); err != nil {
|
|
|
|
log.Errorf("failed to read event: %v", err)
|
|
|
|
reply(w, http.StatusBadRequest, fmt.Errorf("failed to read event"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.LogEntry(*e); err != nil {
|
2015-05-12 00:04:22 +00:00
|
|
|
log.Errorf("failed to write event: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to write event"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, message("events submitted"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getEvents(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2015-07-09 03:57:34 +00:00
|
|
|
f, err := events.FilterFromURL(r.URL.Query())
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to parse filter: %v", err)
|
|
|
|
reply(w, http.StatusBadRequest, fmt.Errorf("failed to parse filter"))
|
|
|
|
return
|
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
es, err := s.a.GetEvents(*f)
|
2015-07-09 03:57:34 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to get events: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError, fmt.Errorf("failed to get events"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
roundtrip.ReplyJSON(w, http.StatusOK, &eventsResponse{Events: es})
|
2015-05-12 00:04:22 +00:00
|
|
|
}
|
|
|
|
|
2015-07-11 00:24:44 +00:00
|
|
|
func (s *APIServer) submitChunks(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
sid := p[0].Value
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
wr, err := s.a.GetChunkWriter(sid)
|
2015-07-11 00:24:44 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to get writer: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to write event"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer wr.Close()
|
|
|
|
|
|
|
|
var rawChunks form.Files
|
|
|
|
err = form.Parse(r, form.FileSlice("chunk", &rawChunks))
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusBadRequest, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(rawChunks) == 0 {
|
|
|
|
reply(w, http.StatusBadRequest,
|
|
|
|
fmt.Errorf("at least one chunk is required"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
// don't let get the error get lost
|
|
|
|
if err := rawChunks.Close(); err != nil {
|
|
|
|
log.Errorf("failed to close files: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// decode chunks
|
|
|
|
chunks := make([]recorder.Chunk, len(rawChunks))
|
|
|
|
for i, c := range rawChunks {
|
|
|
|
data, err := ioutil.ReadAll(c)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to read event: %v", err)
|
|
|
|
reply(w, http.StatusBadRequest, fmt.Errorf("failed to read event"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var ch *recorder.Chunk
|
|
|
|
if err := json.Unmarshal(data, &ch); err != nil {
|
|
|
|
log.Errorf("failed to decode chunk: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to decode chunk"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
chunks[i] = *ch
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := wr.WriteChunks(chunks); err != nil {
|
|
|
|
log.Errorf("failed to decode chunk: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to decode chunk"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, message("chunks submitted"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getChunks(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
sid := p[0].Value
|
|
|
|
|
|
|
|
st, en := r.URL.Query().Get("start"), r.URL.Query().Get("end")
|
|
|
|
start, err := strconv.Atoi(st)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to convert: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to convert"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
end, err := strconv.Atoi(en)
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Errorf("failed to convert: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to convert"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-11 22:21:11 +00:00
|
|
|
re, err := s.a.GetChunkReader(sid)
|
2015-07-11 00:24:44 +00:00
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Errorf("failed to get reader: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to get reader"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer re.Close()
|
|
|
|
|
|
|
|
chunks, err := re.ReadChunks(start, end)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to read chunks: %v", err)
|
|
|
|
reply(w, http.StatusInternalServerError,
|
|
|
|
fmt.Errorf("failed to read chunks"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
roundtrip.ReplyJSON(w, http.StatusOK, &chunksResponse{Chunks: chunks})
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func replyErr(w http.ResponseWriter, e error) {
|
|
|
|
switch err := e.(type) {
|
2015-08-25 17:54:16 +00:00
|
|
|
case *teleport.NotFoundError:
|
2015-03-19 04:13:56 +00:00
|
|
|
reply(w, http.StatusNotFound, message(err.Error()))
|
|
|
|
return
|
2015-08-25 17:54:16 +00:00
|
|
|
case *teleport.MissingParameterError, *teleport.BadParameterError, *form.MissingParameterError, *form.BadParameterError:
|
2015-03-19 04:13:56 +00:00
|
|
|
reply(w, http.StatusBadRequest, message(err.Error()))
|
|
|
|
return
|
|
|
|
}
|
2015-10-31 20:56:40 +00:00
|
|
|
log.Errorf("auth server unexpected error: %v", e)
|
2015-03-19 04:13:56 +00:00
|
|
|
// do not leak the unexpected error to the callee as we are not sure
|
|
|
|
// if it's safe to disclose that information
|
2015-11-13 01:32:45 +00:00
|
|
|
reply(w, http.StatusInternalServerError, message("internal server error: "+e.Error()))
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func reply(w http.ResponseWriter, code int, message interface{}) {
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
w.WriteHeader(code)
|
|
|
|
out, err := json.Marshal(message)
|
|
|
|
if err != nil {
|
|
|
|
out = []byte(`{"msg": "internal marshal error"}`)
|
|
|
|
}
|
|
|
|
w.Write(out)
|
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
func (s *APIServer) upsertRemoteCertificate(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-06-22 21:05:15 +00:00
|
|
|
var id, key string
|
|
|
|
var ttl time.Duration
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
ctype, domainName := p[0].Value, p[1].Value
|
2015-06-22 21:05:15 +00:00
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("key", &key, form.Required()),
|
|
|
|
form.String("id", &id, form.Required()),
|
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-20 21:15:48 +00:00
|
|
|
cert := services.CertificateAuthority{ID: id, PublicKey: []byte(key), DomainName: domainName, Type: ctype}
|
2015-11-18 04:39:19 +00:00
|
|
|
if err := s.a.UpsertRemoteCertificate(cert, ttl); err != nil {
|
2015-06-22 21:05:15 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-18 04:39:19 +00:00
|
|
|
reply(w, http.StatusOK, remoteCertResponse{RemoteCertificate: cert})
|
2015-06-22 21:05:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
func (s *APIServer) getRemoteCertificates(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-20 21:15:48 +00:00
|
|
|
domainName := r.URL.Query().Get("domain")
|
2015-06-22 21:05:15 +00:00
|
|
|
ctype := p[0].Value
|
|
|
|
|
2015-11-20 21:15:48 +00:00
|
|
|
certs, err := s.a.GetRemoteCertificates(ctype, domainName)
|
2015-11-18 04:39:19 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Infof("error: %v", err)
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &remoteCertsResponse{RemoteCertificates: certs})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getTrustedCertificates(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
certType := p[0].Value
|
|
|
|
|
|
|
|
certs, err := s.a.GetTrustedCertificates(certType)
|
2015-06-22 21:05:15 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Infof("error: %v", err)
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-18 04:39:19 +00:00
|
|
|
reply(w, http.StatusOK, &remoteCertsResponse{RemoteCertificates: certs})
|
2015-06-22 21:05:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 04:39:19 +00:00
|
|
|
func (s *APIServer) deleteRemoteCertificate(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-20 21:15:48 +00:00
|
|
|
ctype, domainName, id := p[0].Value, p[1].Value, p[2].Value
|
|
|
|
if err := s.a.DeleteRemoteCertificate(ctype, domainName, id); err != nil {
|
2015-06-22 21:05:15 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("cert '%v' deleted", id)))
|
|
|
|
}
|
|
|
|
|
2015-07-03 20:08:26 +00:00
|
|
|
func (s *APIServer) upsertSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var sid string
|
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("id", &sid, form.Required()),
|
|
|
|
form.Duration("ttl", &ttl))
|
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.UpsertSession(sid, ttl); err != nil {
|
2015-07-03 20:08:26 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, sessionResponse{Session: session.Session{ID: sid}})
|
|
|
|
}
|
|
|
|
|
2015-06-30 23:12:18 +00:00
|
|
|
func (s *APIServer) upsertSessionParty(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var party session.Party
|
|
|
|
|
|
|
|
sid := p[0].Value
|
|
|
|
var ttl time.Duration
|
|
|
|
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("id", &party.ID, form.Required()),
|
|
|
|
form.String("site", &party.Site, form.Required()),
|
|
|
|
form.String("user", &party.User, form.Required()),
|
2015-07-03 00:16:44 +00:00
|
|
|
form.String("server_addr", &party.ServerAddr, form.Required()),
|
2015-06-30 23:14:08 +00:00
|
|
|
form.Time("last_active", &party.LastActive),
|
2015-06-30 23:12:18 +00:00
|
|
|
form.Duration("ttl", &ttl),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.UpsertParty(sid, party, ttl); err != nil {
|
2015-06-30 23:12:18 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, partyResponse{Party: party})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getSessions(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
2015-11-11 22:21:11 +00:00
|
|
|
sessions, err := s.a.GetSessions()
|
2015-06-30 23:12:18 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &sessionsResponse{Sessions: sessions})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) getSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
sid := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
se, err := s.a.GetSession(sid)
|
2015-06-30 23:12:18 +00:00
|
|
|
if err != nil {
|
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, &sessionResponse{Session: *se})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) deleteSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
sid := p[0].Value
|
2015-11-11 22:21:11 +00:00
|
|
|
if err := s.a.DeleteSession(sid); err != nil {
|
2015-06-30 23:12:18 +00:00
|
|
|
replyErr(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message(fmt.Sprintf("session %v was deleted", sid)))
|
|
|
|
}
|
|
|
|
|
2016-01-21 00:05:23 +00:00
|
|
|
func (s *APIServer) getAddUserTokenData(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var token string
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("token", &token, form.Required()),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user, QRImg, hotpFirstValue, err := s.a.GetAddUserTokenData(token)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
reply(w, http.StatusOK, userTokenDataResponse{
|
|
|
|
User: user,
|
|
|
|
QRImg: string(QRImg),
|
|
|
|
HotpFirstValue: hotpFirstValue,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *APIServer) createUserWithToken(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
var token, password string
|
|
|
|
err := form.Parse(r,
|
|
|
|
form.String("token", &token, form.Required()),
|
|
|
|
form.String("password", &password, form.Required()),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.a.CreateUserWithToken(token, password)
|
|
|
|
if err != nil {
|
|
|
|
reply(w, http.StatusInternalServerError, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reply(w, http.StatusOK, message("ok"))
|
|
|
|
}
|
|
|
|
|
|
|
|
type userTokenDataResponse struct {
|
|
|
|
User string `json:"user"`
|
|
|
|
QRImg string `json:"qrimg"`
|
|
|
|
HotpFirstValue string `json:"hotpfirstvalue"`
|
|
|
|
}
|
|
|
|
|
2015-03-02 20:11:23 +00:00
|
|
|
type pubKeyResponse struct {
|
|
|
|
PubKey string `json:"pubkey"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type pubKeysResponse struct {
|
2015-08-25 17:54:16 +00:00
|
|
|
PubKeys []services.AuthorizedKey `json:"pubkeys"`
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type certResponse struct {
|
|
|
|
Cert string `json:"cert"`
|
|
|
|
}
|
|
|
|
|
2015-06-22 21:05:15 +00:00
|
|
|
type remoteCertResponse struct {
|
2015-11-20 21:15:48 +00:00
|
|
|
RemoteCertificate services.CertificateAuthority `hson:"remote_cert"`
|
2015-06-22 21:05:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type remoteCertsResponse struct {
|
2015-11-20 21:15:48 +00:00
|
|
|
RemoteCertificates []services.CertificateAuthority `hson:"remote_certs"`
|
2015-06-22 21:05:15 +00:00
|
|
|
}
|
|
|
|
|
2015-03-02 20:11:23 +00:00
|
|
|
type usersResponse struct {
|
|
|
|
Users []string `json:"users"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type keyPairResponse struct {
|
|
|
|
PrivKey []byte `json:"privkey"`
|
|
|
|
PubKey string `json:"pubkey"`
|
|
|
|
}
|
|
|
|
|
2015-06-30 23:12:18 +00:00
|
|
|
type webSessionResponse struct {
|
2015-03-19 04:13:56 +00:00
|
|
|
SID string `json:"sid"`
|
|
|
|
}
|
|
|
|
|
2015-06-30 23:12:18 +00:00
|
|
|
type webSessionsResponse struct {
|
2015-08-25 17:54:16 +00:00
|
|
|
Keys []services.AuthorizedKey `json:"keys"`
|
2015-05-07 03:10:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
type webTunResponse struct {
|
2015-08-25 17:54:16 +00:00
|
|
|
Tunnel services.WebTun `json:"tunnel"`
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type webTunsResponse struct {
|
2015-08-25 17:54:16 +00:00
|
|
|
Tunnels []services.WebTun `json:"tunnels"`
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type serversResponse struct {
|
2015-08-25 17:54:16 +00:00
|
|
|
Servers []services.Server `json:"servers"`
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
2015-05-07 03:10:44 +00:00
|
|
|
type tokenResponse struct {
|
|
|
|
Token string `json:"token"`
|
|
|
|
}
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
type eventsResponse struct {
|
2015-07-09 03:57:34 +00:00
|
|
|
Events []lunk.Entry `json:"events"`
|
2015-05-12 00:04:22 +00:00
|
|
|
}
|
|
|
|
|
2015-07-11 00:24:44 +00:00
|
|
|
type chunksResponse struct {
|
|
|
|
Chunks []recorder.Chunk `json:"chunks"`
|
|
|
|
}
|
|
|
|
|
2015-06-30 23:12:18 +00:00
|
|
|
type partyResponse struct {
|
|
|
|
Party session.Party `json:"party"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type sessionsResponse struct {
|
|
|
|
Sessions []session.Session `json:"sessions"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type sessionResponse struct {
|
|
|
|
Session session.Session `json:"session"`
|
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
type sealKeyResponse struct {
|
|
|
|
Key encryptor.Key
|
2015-09-12 01:19:20 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 22:04:10 +00:00
|
|
|
type sealKeysResponse struct {
|
|
|
|
Keys []encryptor.Key
|
2015-09-12 01:19:20 +00:00
|
|
|
}
|
|
|
|
|
2015-10-23 00:45:51 +00:00
|
|
|
type upsertPasswordResponse struct {
|
|
|
|
HotpURL string
|
|
|
|
HotpQR []byte
|
|
|
|
}
|
|
|
|
|
2015-12-07 20:05:54 +00:00
|
|
|
type upsertServerArgs struct {
|
|
|
|
Server services.Server
|
|
|
|
TTL time.Duration
|
|
|
|
}
|
|
|
|
|
2015-03-02 20:11:23 +00:00
|
|
|
func message(msg string) map[string]interface{} {
|
|
|
|
return map[string]interface{}{"message": msg}
|
|
|
|
}
|