teleport/lib/auth/srv.go

1030 lines
27 KiB
Go
Raw Normal View History

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"
"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
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codahale/lunk"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/form"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/log"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/roundtrip"
2015-06-30 23:12:18 +00:00
websession "github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/session"
2015-03-14 21:37:21 +00:00
"github.com/gravitational/teleport/Godeps/_workspace/src/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
a *AuthWithRoles
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
}
func NewAPIServer(a *AuthWithRoles) *APIServer {
2015-03-02 20:11:23 +00:00
srv := &APIServer{
a: a,
2015-03-02 20:11:23 +00:00
}
srv.Router = *httprouter.New()
// Auth is for operations involving CA
srv.POST("/v1/ca/host/keys", srv.resetHostCA)
srv.POST("/v1/ca/user/keys", srv.resetUserCA)
2015-03-02 20:11:23 +00:00
// Retrieving authority public keys
srv.GET("/v1/ca/host/keys/pub", srv.getHostCAPub)
srv.GET("/v1/ca/user/keys/pub", srv.getUserCAPub)
2015-03-02 20:11:23 +00:00
// Generating certificates for user and host authorities
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
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
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
srv.POST("/v1/keypair", srv.generateKeyPair)
// Operations on remote authorities we trust
srv.POST("/v1/ca/remote/:type/hosts/:fqdn", srv.upsertRemoteCert)
srv.DELETE("/v1/ca/remote/:type/hosts/:fqdn/:id", srv.deleteRemoteCert)
srv.GET("/v1/ca/remote/:type", srv.getRemoteCerts)
// 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)
srv.GET("/v1/users/:user/web/sessions", srv.getWebSessions)
srv.DELETE("/v1/users/:user/web/sessions/:sid", srv.deleteWebSession)
// 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
srv.POST("/v1/servers", srv.upsertServer)
srv.GET("/v1/servers", srv.getServers)
2015-03-02 20:11:23 +00:00
// Tokens
srv.POST("/v1/tokens", srv.generateToken)
srv.POST("/v1/tokens/register", srv.registerUsingToken)
srv.POST("/v1/tokens/register/auth", srv.registerNewAuthServer)
// 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)
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)
// Backend Keys
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-03-02 20:11:23 +00:00
return srv
}
func (s *APIServer) getSealKeys(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
keys, err := s.a.GetSealKeys()
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, sealKeysResponse{Keys: keys})
}
func (s *APIServer) getSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
id := p[0].Value
key, err := s.a.GetSealKey(id)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, sealKeyResponse{Key: key})
}
func (s *APIServer) deleteSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
id := p[0].Value
err := s.a.DeleteSealKey(id)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, message("Key "+id+" was deleted"))
}
func (s *APIServer) addSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var keyJSON string
err := form.Parse(r,
form.String("key", &keyJSON, form.Required()),
)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
var key encryptor.Key
if err := json.Unmarshal([]byte(keyJSON), &key); err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
err = s.a.AddSealKey(key)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, message("ok"))
}
func (s *APIServer) generateSealKey(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var name string
err := form.Parse(r,
form.String("name", &name, form.Required()),
)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
key, err := s.a.GenerateSealKey(name)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, sealKeyResponse{Key: key})
}
func (s *APIServer) upsertServer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var id, addr, hostname string
var ttl time.Duration
err := form.Parse(r,
form.String("id", &id, form.Required()),
form.String("addr", &addr, form.Required()),
form.String("hostname", &hostname, form.Required()),
form.Duration("ttl", &ttl),
)
if err != nil {
replyErr(w, err)
return
}
server := services.Server{
ID: id,
Addr: addr,
Hostname: hostname,
}
if err := s.a.UpsertServer(server, ttl); err != nil {
replyErr(w, err)
return
}
reply(w, http.StatusOK, message("server upserted"))
}
func (s *APIServer) getServers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
servers, err := s.a.GetServers()
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)
if err != nil {
replyErr(w, err)
return
}
if err := s.a.UpsertWebTun(*t, ttl); err != nil {
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
err := s.a.DeleteWebTun(prefix)
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
wt, err := s.a.GetWebTun(prefix)
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) {
ws, err := s.a.GetWebTuns()
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
err := s.a.DeleteWebSession(user, websession.SecureID(sid))
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
ws, err := s.a.GetWebSession(user, websession.SecureID(sid))
if err != nil {
replyErr(w, err)
return
}
2015-06-30 23:12:18 +00:00
reply(w, http.StatusOK, &webSessionResponse{SID: string(ws.SID)})
}
func (s *APIServer) getWebSessions(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
user := p[0].Value
keys, err := s.a.GetWebSessionsKeys(user)
if err != nil {
replyErr(w, err)
return
}
2015-06-30 23:12:18 +00:00
reply(w, http.StatusOK, &webSessionsResponse{Keys: keys})
}
func (s *APIServer) signIn(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
ws, err := s.a.SignIn(user, []byte(pass))
if err != nil {
replyErr(w, err)
return
}
2015-06-30 23:12:18 +00:00
reply(w, http.StatusOK, &webSessionResponse{SID: string(ws.SID)})
}
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
hotpURL, hotpQR, err := s.a.UpsertPassword(user, []byte(pass))
if err != nil {
replyErr(w, err)
return
}
reply(w, http.StatusOK,
&upsertPasswordResponse{HotpURL: hotpURL, HotpQR: hotpQR})
}
func (s *APIServer) checkPassword(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var pass string
var hotpToken string
err := form.Parse(r,
form.String("password", &pass, form.Required()),
form.String("hotpToken", &hotpToken, form.Required()),
)
if err != nil {
replyErr(w, err)
return
}
user := p[0].Value
if err := s.a.CheckPassword(user, []byte(pass), hotpToken); err != nil {
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 {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
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 {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, certResponse{Cert: string(cert)})
}
func (s *APIServer) getUsers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
users, err := s.a.GetUsers()
2015-03-02 20:11:23 +00:00
if err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, &usersResponse{Users: users})
}
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
if err := s.a.DeleteUser(user); err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, message(fmt.Sprintf("user '%v' deleted", user)))
}
func (s *APIServer) getUserKeys(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
keys, err := s.a.GetUserKeys(p[0].Value)
2015-03-02 20:11:23 +00:00
if err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, &pubKeysResponse{PubKeys: keys})
}
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
if err := s.a.DeleteUserKey(user, keyID); err != nil {
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)))
}
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 {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
priv, pub, err := s.a.GenerateKeyPair(pass)
2015-03-02 20:11:23 +00:00
if err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, &keyPairResponse{PrivKey: priv, PubKey: string(pub)})
}
func (s *APIServer) resetHostCA(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 {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
if err := s.a.ResetHostCA(pass); err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, message("host CA regenerated"))
}
func (s *APIServer) resetUserCA(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 {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
if err := s.a.ResetUserCA(pass); err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, message("user CA regenerated"))
}
func (s *APIServer) getHostCAPub(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
bytes, err := s.a.GetHostCAPub()
2015-03-02 20:11:23 +00:00
if err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, pubKeyResponse{PubKey: string(bytes)})
}
func (s *APIServer) getUserCAPub(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
bytes, err := s.a.GetUserCAPub()
2015-03-02 20:11:23 +00:00
if err != nil {
replyErr(w, err)
2015-03-02 20:11:23 +00:00
return
}
reply(w, http.StatusOK, pubKeyResponse{PubKey: string(bytes)})
}
func (s *APIServer) generateHostCert(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
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()),
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
}
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)})
}
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
}
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)})
}
func (s *APIServer) generateToken(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
var fqdn, role string
var ttl time.Duration
err := form.Parse(r,
form.String("fqdn", &fqdn, form.Required()),
form.String("role", &role, form.Required()),
form.Duration("ttl", &ttl))
if err != nil {
reply(w, http.StatusBadRequest, err.Error())
2015-11-16 05:21:34 +00:00
return
}
token, err := s.a.GenerateToken(fqdn, role, ttl)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, tokenResponse{Token: string(token)})
}
func (s *APIServer) registerUsingToken(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
var token, fqdn, role string
err := form.Parse(r,
form.String("token", &token, form.Required()),
form.String("fqdn", &fqdn, form.Required()),
form.String("role", &role, form.Required()),
)
if err != nil {
reply(w, http.StatusBadRequest, err.Error())
2015-11-16 05:21:34 +00:00
return
}
keys, err := s.a.RegisterUsingToken(token, fqdn, role)
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) {
var token, fqdn, pkeyJSON string
err := form.Parse(r,
form.String("token", &token, form.Required()),
form.String("fqdn", &fqdn, form.Required()),
form.String("key", &pkeyJSON, form.Required()),
)
if err != nil {
reply(w, http.StatusBadRequest, err.Error())
2015-11-16 05:21:34 +00:00
return
}
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
}
key, err := s.a.RegisterNewAuthServer(fqdn, token, pkey)
if err != nil {
reply(w, http.StatusInternalServerError, err.Error())
return
}
reply(w, http.StatusOK, key)
}
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
}
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
}
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
}
if err := s.a.LogEntry(*e); err != nil {
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
}
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-07-11 00:24:44 +00:00
func (s *APIServer) submitChunks(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
sid := p[0].Value
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
}
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})
}
func replyErr(w http.ResponseWriter, e error) {
switch err := e.(type) {
2015-08-25 17:54:16 +00:00
case *teleport.NotFoundError:
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:
reply(w, http.StatusBadRequest, message(err.Error()))
return
}
2015-10-31 20:56:40 +00:00
log.Errorf("auth server unexpected error: %v", e)
// do not leak the unexpected error to the callee as we are not sure
// if it's safe to disclose that information
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)
}
func (s *APIServer) upsertRemoteCert(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var id, key string
var ttl time.Duration
ctype, fqdn := p[0].Value, p[1].Value
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-08-25 17:54:16 +00:00
cert := services.RemoteCert{ID: id, Value: []byte(key), FQDN: fqdn, Type: ctype}
if err := s.a.UpsertRemoteCert(cert, ttl); err != nil {
replyErr(w, err)
return
}
reply(w, http.StatusOK, remoteCertResponse{RemoteCert: cert})
}
func (s *APIServer) getRemoteCerts(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
fqdn := r.URL.Query().Get("fqdn")
ctype := p[0].Value
certs, err := s.a.GetRemoteCerts(ctype, fqdn)
if err != nil {
fmt.Printf("error: %v", err)
log.Infof("error: %v", err)
replyErr(w, err)
return
}
reply(w, http.StatusOK, &remoteCertsResponse{RemoteCerts: certs})
}
func (s *APIServer) deleteRemoteCert(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctype, fqdn, id := p[0].Value, p[1].Value, p[2].Value
if err := s.a.DeleteRemoteCert(ctype, fqdn, id); err != nil {
replyErr(w, err)
return
}
reply(w, http.StatusOK, message(fmt.Sprintf("cert '%v' deleted", id)))
}
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
}
if err := s.a.UpsertSession(sid, ttl); err != nil {
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
}
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) {
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
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
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)))
}
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"`
}
type remoteCertResponse struct {
2015-08-25 17:54:16 +00:00
RemoteCert services.RemoteCert `hson:"remote_cert"`
}
type remoteCertsResponse struct {
2015-08-25 17:54:16 +00:00
RemoteCerts []services.RemoteCert `hson:"remote_certs"`
}
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 {
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"`
}
type webTunResponse struct {
2015-08-25 17:54:16 +00:00
Tunnel services.WebTun `json:"tunnel"`
}
type webTunsResponse struct {
2015-08-25 17:54:16 +00:00
Tunnels []services.WebTun `json:"tunnels"`
}
type serversResponse struct {
2015-08-25 17:54:16 +00:00
Servers []services.Server `json:"servers"`
}
type tokenResponse struct {
Token string `json:"token"`
}
type eventsResponse struct {
2015-07-09 03:57:34 +00:00
Events []lunk.Entry `json:"events"`
}
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"`
}
type sealKeyResponse struct {
Key encryptor.Key
}
type sealKeysResponse struct {
Keys []encryptor.Key
}
type upsertPasswordResponse struct {
HotpURL string
HotpQR []byte
}
2015-03-02 20:11:23 +00:00
func message(msg string) map[string]interface{} {
return map[string]interface{}{"message": msg}
}