2015-03-02 20:11:23 +00:00
|
|
|
// package auth implements certificate signing authority and access control server
|
|
|
|
// Authority server is composed of several parts:
|
|
|
|
//
|
|
|
|
// * Authority server itself that implements signing and acl logic
|
|
|
|
// * HTTP server wrapper for authority server
|
|
|
|
// * HTTP client wrapper
|
|
|
|
//
|
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
2015-03-19 04:13:56 +00:00
|
|
|
"fmt"
|
2015-03-02 20:11:23 +00:00
|
|
|
"time"
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/session"
|
|
|
|
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/mailgun/lemma/secret"
|
2015-10-05 14:33:25 +00:00
|
|
|
"github.com/gravitational/teleport/lib/backend/encryptedbk"
|
2015-10-05 17:36:55 +00:00
|
|
|
"github.com/gravitational/teleport/lib/services"
|
2015-03-02 20:11:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Authority implements minimal key-management facility for generating OpenSSH
|
|
|
|
//compatible public/private key pairs and OpenSSH certificates
|
|
|
|
type Authority interface {
|
2015-03-19 04:13:56 +00:00
|
|
|
GenerateKeyPair(passphrase string) (privKey []byte, pubKey []byte, err error)
|
2015-03-02 20:11:23 +00:00
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
// GenerateHostCert generates host certificate, it takes pkey as a signing
|
|
|
|
// private key (host certificate authority)
|
2015-03-02 20:11:23 +00:00
|
|
|
GenerateHostCert(pkey, key []byte, id, hostname string, ttl time.Duration) ([]byte, error)
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
// GenerateHostCert generates user certificate, it takes pkey as a signing
|
|
|
|
// private key (user certificate authority)
|
2015-03-02 20:11:23 +00:00
|
|
|
GenerateUserCert(pkey, key []byte, id, username string, ttl time.Duration) ([]byte, error)
|
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
type Session struct {
|
|
|
|
SID session.SecureID
|
|
|
|
PID session.PlainID
|
2015-08-25 17:54:16 +00:00
|
|
|
WS services.WebSession
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
2015-09-12 01:19:20 +00:00
|
|
|
func NewAuthServer(bk *encryptedbk.ReplicatedBackend, a Authority, scrt secret.SecretService) *AuthServer {
|
2015-08-25 17:54:16 +00:00
|
|
|
as := AuthServer{}
|
|
|
|
|
|
|
|
as.bk = bk
|
2015-08-27 14:39:33 +00:00
|
|
|
as.Authority = a
|
2015-08-25 17:54:16 +00:00
|
|
|
as.scrt = scrt
|
|
|
|
|
2015-08-27 14:39:33 +00:00
|
|
|
as.CAService = services.NewCAService(as.bk)
|
|
|
|
as.LockService = services.NewLockService(as.bk)
|
|
|
|
as.PresenceService = services.NewPresenceService(as.bk)
|
|
|
|
as.ProvisioningService = services.NewProvisioningService(as.bk)
|
|
|
|
as.UserService = services.NewUserService(as.bk)
|
|
|
|
as.WebService = services.NewWebService(as.bk)
|
2015-09-12 01:19:20 +00:00
|
|
|
as.BkKeysService = services.NewBkKeysService(as.bk)
|
2015-08-25 17:54:16 +00:00
|
|
|
|
|
|
|
return &as
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
// AuthServer implements key signing, generation and ACL functionality
|
|
|
|
// used by teleport
|
2015-03-02 20:11:23 +00:00
|
|
|
type AuthServer struct {
|
2015-09-12 01:19:20 +00:00
|
|
|
bk *encryptedbk.ReplicatedBackend
|
2015-08-27 14:39:33 +00:00
|
|
|
Authority
|
2015-09-06 14:54:34 +00:00
|
|
|
scrt secret.SecretService
|
2015-08-25 17:54:16 +00:00
|
|
|
|
2015-08-27 14:39:33 +00:00
|
|
|
*services.CAService
|
|
|
|
*services.LockService
|
|
|
|
*services.PresenceService
|
|
|
|
*services.ProvisioningService
|
|
|
|
*services.UserService
|
|
|
|
*services.WebService
|
2015-09-12 01:19:20 +00:00
|
|
|
*services.BkKeysService
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpsertUserKey takes user's public key, generates certificate for it
|
2015-05-12 00:04:22 +00:00
|
|
|
// and adds it to the authorized keys database. It returns certificate signed
|
|
|
|
// by user CA in case of success, error otherwise. The certificate will be
|
|
|
|
// valid for the duration of the ttl passed in.
|
|
|
|
func (s *AuthServer) UpsertUserKey(
|
2015-08-25 17:54:16 +00:00
|
|
|
user string, key services.AuthorizedKey, ttl time.Duration) ([]byte, error) {
|
2015-05-12 00:04:22 +00:00
|
|
|
|
2015-03-02 20:11:23 +00:00
|
|
|
cert, err := s.GenerateUserCert(key.Value, key.ID, user, ttl)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
key.Value = cert
|
2015-08-27 14:39:33 +00:00
|
|
|
if err := s.UserService.UpsertUserKey(user, key, ttl); err != nil {
|
2015-03-02 20:11:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cert, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResetHostCA generates host certificate authority and updates the backend
|
|
|
|
func (s *AuthServer) ResetHostCA(pass string) error {
|
2015-08-27 14:39:33 +00:00
|
|
|
priv, pub, err := s.Authority.GenerateKeyPair(pass)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.CAService.UpsertHostCA(services.CA{Pub: pub, Priv: priv})
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ResetHostCA generates user certificate authority and updates the backend
|
|
|
|
func (s *AuthServer) ResetUserCA(pass string) error {
|
2015-08-27 14:39:33 +00:00
|
|
|
priv, pub, err := s.Authority.GenerateKeyPair(pass)
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.CAService.UpsertUserCA(services.CA{Pub: pub, Priv: priv})
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
// GenerateHostCert generates host certificate, it takes pkey as a signing
|
|
|
|
// private key (host certificate authority)
|
|
|
|
func (s *AuthServer) GenerateHostCert(
|
|
|
|
key []byte, id, hostname string, ttl time.Duration) ([]byte, error) {
|
|
|
|
|
2015-08-27 14:39:33 +00:00
|
|
|
hk, err := s.CAService.GetHostCA()
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.Authority.GenerateHostCert(hk.Priv, key, id, hostname, ttl)
|
2015-03-02 20:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 00:04:22 +00:00
|
|
|
// GenerateHostCert generates user certificate, it takes pkey as a signing
|
|
|
|
// private key (user certificate authority)
|
|
|
|
func (s *AuthServer) GenerateUserCert(
|
|
|
|
key []byte, id, username string, ttl time.Duration) ([]byte, error) {
|
|
|
|
|
2015-08-27 14:39:33 +00:00
|
|
|
hk, err := s.CAService.GetUserCA()
|
2015-03-02 20:11:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.Authority.GenerateUserCert(hk.Priv, key, id, username, ttl)
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-23 20:34:09 +00:00
|
|
|
func (s *AuthServer) SignIn(user string, password []byte) (*Session, error) {
|
|
|
|
if err := s.CheckPasswordWOToken(user, password); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
sess, err := s.NewWebSession(user)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-10-27 23:30:16 +00:00
|
|
|
if err := s.UpsertWebSession(user, sess, WebSessionTTL); err != nil {
|
2015-03-19 04:13:56 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return sess, nil
|
|
|
|
}
|
|
|
|
|
2015-05-07 03:10:44 +00:00
|
|
|
func (s *AuthServer) GenerateToken(fqdn string, ttl time.Duration) (string, error) {
|
|
|
|
p, err := session.NewID(s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
if err := s.ProvisioningService.UpsertToken(string(p.PID), fqdn, ttl); err != nil {
|
2015-05-07 03:10:44 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return string(p.SID), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *AuthServer) ValidateToken(token, fqdn string) error {
|
|
|
|
pid, err := session.DecodeSID(session.SecureID(token), s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
out, err := s.ProvisioningService.GetToken(string(pid))
|
2015-05-07 03:10:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if out != fqdn {
|
|
|
|
return fmt.Errorf("fqdn does not match")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *AuthServer) DeleteToken(token string) error {
|
|
|
|
pid, err := session.DecodeSID(session.SecureID(token), s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.ProvisioningService.DeleteToken(string(pid))
|
2015-05-07 03:10:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-19 04:13:56 +00:00
|
|
|
func (s *AuthServer) NewWebSession(user string) (*Session, error) {
|
|
|
|
p, err := session.NewID(s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
priv, pub, err := s.GenerateKeyPair("")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
hk, err := s.CAService.GetUserCA()
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-10-27 23:30:16 +00:00
|
|
|
cert, err := s.Authority.GenerateUserCert(hk.Priv, pub, user, user, WebSessionTTL)
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
sess := &Session{
|
|
|
|
SID: p.SID,
|
|
|
|
PID: p.PID,
|
2015-08-25 17:54:16 +00:00
|
|
|
WS: services.WebSession{Priv: priv, Pub: cert},
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
return sess, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *AuthServer) UpsertWebSession(user string, sess *Session, ttl time.Duration) error {
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.WebService.UpsertWebSession(user, string(sess.PID), sess.WS, ttl)
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *AuthServer) GetWebSession(user string, sid session.SecureID) (*Session, error) {
|
|
|
|
pid, err := session.DecodeSID(sid, s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
ws, err := s.WebService.GetWebSession(user, string(pid))
|
2015-03-19 04:13:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &Session{
|
|
|
|
SID: sid,
|
|
|
|
PID: pid,
|
|
|
|
WS: *ws,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *AuthServer) DeleteWebSession(user string, sid session.SecureID) error {
|
|
|
|
pid, err := session.DecodeSID(sid, s.scrt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-08-27 14:39:33 +00:00
|
|
|
return s.WebService.DeleteWebSession(user, string(pid))
|
2015-03-19 04:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2015-10-27 23:30:16 +00:00
|
|
|
Week = time.Hour * 24 * 7
|
|
|
|
WebSessionTTL = time.Hour * 10
|
2015-03-19 04:13:56 +00:00
|
|
|
)
|