mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 17:23:22 +00:00
Added --compat=oldssh flag to generate user certificates without roles.
This commit is contained in:
parent
64544a876b
commit
7e17b6f9a7
10
constants.go
10
constants.go
|
@ -166,3 +166,13 @@ const (
|
|||
|
||||
// MaxEnvironmentFileLines is the maximum number of lines in a environment file.
|
||||
const MaxEnvironmentFileLines = 1000
|
||||
|
||||
const (
|
||||
// CompatibilityOldSSH is used to make Teleport interoperate with older
|
||||
// versions of OpenSSH.
|
||||
CompatibilityOldSSH = "oldssh"
|
||||
|
||||
// CompatibilityNone is used for normal Teleport operation without any
|
||||
// compatibility modes.
|
||||
CompatibilityNone = ""
|
||||
)
|
||||
|
|
|
@ -337,7 +337,7 @@ func (i *TeleInstance) CreateEx(trustedSecrets []*InstanceSecrets, tconf *servic
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
user.Key.Cert, err = auth.GenerateUserCert(user.Key.Pub, teleUser, logins, ttl, true)
|
||||
user.Key.Cert, err = auth.GenerateUserCert(user.Key.Pub, teleUser, logins, ttl, true, teleport.CompatibilityNone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -715,9 +715,10 @@ func (s *APIServer) generateHostCert(auth ClientI, w http.ResponseWriter, r *htt
|
|||
}
|
||||
|
||||
type generateUserCertReq struct {
|
||||
Key []byte `json:"key"`
|
||||
User string `json:"user"`
|
||||
TTL time.Duration `json:"ttl"`
|
||||
Key []byte `json:"key"`
|
||||
User string `json:"user"`
|
||||
TTL time.Duration `json:"ttl"`
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
func (s *APIServer) generateUserCert(auth ClientI, w http.ResponseWriter, r *http.Request, _ httprouter.Params, version string) (interface{}, error) {
|
||||
|
@ -725,7 +726,11 @@ func (s *APIServer) generateUserCert(auth ClientI, w http.ResponseWriter, r *htt
|
|||
if err := httplib.ReadJSON(r, &req); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert, err := auth.GenerateUserCert(req.Key, req.User, req.TTL)
|
||||
compatibility, err := utils.CheckCompatibilityFlag(req.Compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert, err := auth.GenerateUserCert(req.Key, req.User, req.TTL, compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
authServer, userClient := s.newServerWithAuthorizer(c, authorizer)
|
||||
defer authServer.Close()
|
||||
|
||||
cert, err = userClient.GenerateUserCert(pub, "user1", time.Hour)
|
||||
cert, err = userClient.GenerateUserCert(pub, "user1", time.Hour, teleport.CompatibilityNone)
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(err.Error(), Equals, "auth API: access denied [00]")
|
||||
|
||||
|
@ -245,7 +245,7 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
authServer2, userClient2 := s.newServerWithAuthorizer(c, authorizer)
|
||||
defer authServer2.Close()
|
||||
|
||||
cert, err = userClient2.GenerateUserCert(pub, "user1", time.Hour)
|
||||
cert, err = userClient2.GenerateUserCert(pub, "user1", time.Hour, teleport.CompatibilityNone)
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(err, ErrorMatches, ".*cannot request a certificate for user1")
|
||||
|
||||
|
@ -255,7 +255,7 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
authServer3, userClient3 := s.newServerWithAuthorizer(c, authorizer)
|
||||
defer authServer3.Close()
|
||||
|
||||
cert, err = userClient3.GenerateUserCert(pub, "user1", 40*time.Hour)
|
||||
cert, err = userClient3.GenerateUserCert(pub, "user1", 40*time.Hour, teleport.CompatibilityNone)
|
||||
c.Assert(err, IsNil)
|
||||
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(cert)
|
||||
c.Assert(err, IsNil)
|
||||
|
@ -278,7 +278,7 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
authServer4, userClient4 := s.newServerWithAuthorizer(c, authorizer)
|
||||
defer authServer4.Close()
|
||||
|
||||
cert, err = userClient4.GenerateUserCert(pub, "user1", 1*time.Hour)
|
||||
cert, err = userClient4.GenerateUserCert(pub, "user1", 1*time.Hour, teleport.CompatibilityNone)
|
||||
c.Assert(err, IsNil)
|
||||
parsedKey, _, _, _, err = ssh.ParseAuthorizedKey(cert)
|
||||
c.Assert(err, IsNil)
|
||||
|
@ -289,7 +289,7 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
c.Assert(exists, Equals, true)
|
||||
|
||||
// apply HTTP Auth to generate user cert:
|
||||
cert, err = userClient3.GenerateUserCert(pub, "user1", time.Hour)
|
||||
cert, err = userClient3.GenerateUserCert(pub, "user1", time.Hour, teleport.CompatibilityNone)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
_, _, _, _, err = ssh.ParseAuthorizedKey(cert)
|
||||
|
|
|
@ -215,7 +215,7 @@ func (s *AuthServer) GenerateHostCert(hostPublicKey []byte, hostID, nodeName, cl
|
|||
|
||||
// GenerateUserCert generates user certificate, it takes pkey as a signing
|
||||
// private key (user certificate authority)
|
||||
func (s *AuthServer) GenerateUserCert(key []byte, user services.User, allowedLogins []string, ttl time.Duration, canForwardAgents bool) ([]byte, error) {
|
||||
func (s *AuthServer) GenerateUserCert(key []byte, user services.User, allowedLogins []string, ttl time.Duration, canForwardAgents bool, compatibility string) ([]byte, error) {
|
||||
ca, err := s.Trust.GetCertAuthority(services.CertAuthID{
|
||||
Type: services.UserCA,
|
||||
DomainName: s.DomainName,
|
||||
|
@ -228,13 +228,14 @@ func (s *AuthServer) GenerateUserCert(key []byte, user services.User, allowedLog
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return s.Authority.GenerateUserCert(services.UserCertParams{
|
||||
PrivateCASigningKey: privateKey,
|
||||
PublicUserKey: key,
|
||||
Username: user.GetName(),
|
||||
AllowedLogins: allowedLogins,
|
||||
TTL: ttl,
|
||||
PrivateCASigningKey: privateKey,
|
||||
PublicUserKey: key,
|
||||
Username: user.GetName(),
|
||||
AllowedLogins: allowedLogins,
|
||||
TTL: ttl,
|
||||
Roles: user.GetRoles(),
|
||||
Compatibility: compatibility,
|
||||
PermitAgentForwarding: canForwardAgents,
|
||||
Roles: user.GetRoles(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ func (a *AuthWithRoles) GenerateHostCert(
|
|||
return a.authServer.GenerateHostCert(key, hostID, nodeName, clusterName, roles, ttl)
|
||||
}
|
||||
|
||||
func (a *AuthWithRoles) GenerateUserCert(key []byte, username string, ttl time.Duration) ([]byte, error) {
|
||||
func (a *AuthWithRoles) GenerateUserCert(key []byte, username string, ttl time.Duration, compatibility string) ([]byte, error) {
|
||||
if err := a.currentUserAction(username); err != nil {
|
||||
return nil, trace.AccessDenied("%v cannot request a certificate for %v", a.user.GetName(), username)
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ func (a *AuthWithRoles) GenerateUserCert(key []byte, username string, ttl time.D
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return a.authServer.GenerateUserCert(
|
||||
key, user, allowedLogins, sessionTTL, checker.CanForwardAgents())
|
||||
key, user, allowedLogins, sessionTTL, checker.CanForwardAgents(), compatibility)
|
||||
}
|
||||
|
||||
func (a *AuthWithRoles) CreateSignupToken(user services.UserV1) (token string, e error) {
|
||||
|
|
|
@ -742,17 +742,16 @@ func (c *Client) GenerateHostCert(
|
|||
return []byte(cert), nil
|
||||
}
|
||||
|
||||
// GenerateUserCert takes the public key in the Open SSH ``authorized_keys``
|
||||
// plain text format, signs it using User Certificate Authority signing key and returns the
|
||||
// resulting certificate.
|
||||
func (c *Client) GenerateUserCert(
|
||||
key []byte, user string, ttl time.Duration) ([]byte, error) {
|
||||
|
||||
// GenerateUserCert takes the public key in the OpenSSH `authorized_keys` plain
|
||||
// text format, signs it using User Certificate Authority signing key and
|
||||
// returns the resulting certificate.
|
||||
func (c *Client) GenerateUserCert(key []byte, user string, ttl time.Duration, compatibility string) ([]byte, error) {
|
||||
out, err := c.PostJSON(c.Endpoint("ca", "user", "certs"),
|
||||
generateUserCertReq{
|
||||
Key: key,
|
||||
User: user,
|
||||
TTL: ttl,
|
||||
Key: key,
|
||||
User: user,
|
||||
TTL: ttl,
|
||||
Compatibility: compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -1610,10 +1609,10 @@ type IdentityService interface {
|
|||
// resulting certificate.
|
||||
GenerateHostCert(key []byte, hostID, nodeName, clusterName string, roles teleport.Roles, ttl time.Duration) ([]byte, error)
|
||||
|
||||
// GenerateUserCert takes the public key in the Open SSH ``authorized_keys``
|
||||
// GenerateUserCert takes the public key in the OpenSSH `authorized_keys`
|
||||
// plain text format, signs it using User Certificate Authority signing key and returns the
|
||||
// resulting certificate.
|
||||
GenerateUserCert(key []byte, user string, ttl time.Duration) ([]byte, error)
|
||||
GenerateUserCert(key []byte, user string, ttl time.Duration, compatibility string) ([]byte, error)
|
||||
|
||||
// GetSignupTokenData returns token data for a valid token
|
||||
GetSignupTokenData(token string) (user string, otpQRCode []byte, e error)
|
||||
|
|
|
@ -209,18 +209,23 @@ func (n *nauth) GenerateUserCert(c services.UserCertParams) ([]byte, error) {
|
|||
cert.Permissions.Extensions[teleport.CertExtensionPermitAgentForwarding] = ""
|
||||
}
|
||||
if len(c.Roles) != 0 {
|
||||
roles, err := services.MarshalCertRoles(c.Roles)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
// if we are requesting a certificate with support for older versions of OpenSSH
|
||||
// don't add roles to certificate extensions, due to a bug in <= OpenSSH 7.1
|
||||
// https://bugzilla.mindrot.org/show_bug.cgi?id=2387
|
||||
if c.Compatibility != teleport.CompatibilityOldSSH {
|
||||
roles, err := services.MarshalCertRoles(c.Roles)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert.Permissions.Extensions[teleport.CertExtensionTeleportRoles] = roles
|
||||
}
|
||||
cert.Permissions.Extensions[teleport.CertExtensionTeleportRoles] = roles
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(c.PrivateCASigningKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if err := cert.SignCert(rand.Reader, signer); err != nil {
|
||||
return nil, err
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return ssh.MarshalAuthorizedKey(cert), nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
package native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -36,6 +37,7 @@ type NativeSuite struct {
|
|||
}
|
||||
|
||||
var _ = Suite(&NativeSuite{})
|
||||
var _ = fmt.Printf
|
||||
|
||||
func (s *NativeSuite) SetUpSuite(c *C) {
|
||||
utils.InitLoggerForTests()
|
||||
|
@ -139,3 +141,58 @@ func (s *NativeSuite) TestBuildPrincipals(c *C) {
|
|||
c.Assert(hostCertificate.ValidPrincipals, DeepEquals, tt.outValidPrincipals)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserCertCompatibility makes sure the compatibility flag can be used to
|
||||
// add to remove roles from certificate extensions.
|
||||
func (s *NativeSuite) TestUserCertCompatibility(c *C) {
|
||||
priv, pub, err := s.suite.A.GenerateKeyPair("")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
tests := []struct {
|
||||
inCompatibility string
|
||||
outHasRoles bool
|
||||
}{
|
||||
// 0 - no compatibility, has roles
|
||||
{
|
||||
"",
|
||||
true,
|
||||
},
|
||||
// 1 - no compatibility, has roles
|
||||
{
|
||||
"invalid",
|
||||
true,
|
||||
},
|
||||
// 2 - compatibility, has roles
|
||||
{
|
||||
"oldssh",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
// run tests
|
||||
for i, tt := range tests {
|
||||
comment := Commentf("Test %v", i)
|
||||
|
||||
userCertificateBytes, err := s.suite.A.GenerateUserCert(services.UserCertParams{
|
||||
PrivateCASigningKey: priv,
|
||||
PublicUserKey: pub,
|
||||
Username: "user",
|
||||
AllowedLogins: []string{"centos", "root"},
|
||||
TTL: time.Hour,
|
||||
Roles: []string{"foo"},
|
||||
Compatibility: tt.inCompatibility,
|
||||
PermitAgentForwarding: true,
|
||||
})
|
||||
c.Assert(err, IsNil, comment)
|
||||
|
||||
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(userCertificateBytes)
|
||||
c.Assert(err, IsNil, comment)
|
||||
|
||||
userCertificate, ok := publicKey.(*ssh.Certificate)
|
||||
c.Assert(ok, Equals, true, comment)
|
||||
|
||||
// check if we added the roles extension
|
||||
_, ok = userCertificate.Extensions[teleport.CertExtensionTeleportRoles]
|
||||
c.Assert(ok, Equals, tt.outHasRoles, comment)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ func (a *AuthServer) ValidateOIDCAuthCallback(q url.Values) (*OIDCAuthResponse,
|
|||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert, err := a.GenerateUserCert(req.PublicKey, user, allowedLogins, certTTL, roles.CanForwardAgents())
|
||||
cert, err := a.GenerateUserCert(req.PublicKey, user, allowedLogins, certTTL, roles.CanForwardAgents(), req.Compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ func (a *AuthServer) ValidateSAMLResponse(samlResponse string) (*SAMLAuthRespons
|
|||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cert, err := a.GenerateUserCert(request.PublicKey, user, allowedLogins, certTTL, roles.CanForwardAgents())
|
||||
cert, err := a.GenerateUserCert(request.PublicKey, user, allowedLogins, certTTL, roles.CanForwardAgents(), request.Compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -172,6 +172,9 @@ type Config struct {
|
|||
// CachePolicy defines local caching policy in case if discovery goes down
|
||||
// by default does not use caching
|
||||
CachePolicy *CachePolicy
|
||||
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string
|
||||
}
|
||||
|
||||
// CachePolicy defines cache policy for local clients
|
||||
|
@ -1010,7 +1013,8 @@ func (tc *TeleportClient) Login() (*CertAuthMethod, error) {
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// generate a new keypair. the public key will be signed via proxy if our password+HOTP are legit
|
||||
// generate a new keypair. the public key will be signed via proxy if our
|
||||
// password+OTP are legit
|
||||
key, err := tc.MakeKey()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -1124,14 +1128,16 @@ func (tc *TeleportClient) directLogin(secondFactorType string, pub []byte) (*SSH
|
|||
}
|
||||
|
||||
// ask the CA (via proxy) to sign our public key:
|
||||
response, err := SSHAgentLogin(httpsProxyHostPort,
|
||||
response, err := SSHAgentLogin(
|
||||
httpsProxyHostPort,
|
||||
tc.Config.Username,
|
||||
password,
|
||||
otpToken,
|
||||
pub,
|
||||
tc.KeyTTL,
|
||||
tc.InsecureSkipVerify,
|
||||
certPool)
|
||||
certPool,
|
||||
tc.Compatibility)
|
||||
|
||||
return response, trace.Wrap(err)
|
||||
}
|
||||
|
@ -1141,8 +1147,15 @@ func (tc *TeleportClient) ssoLogin(connectorID string, pub []byte, protocol stri
|
|||
log.Debugf("samlLogin start")
|
||||
// ask the CA (via proxy) to sign our public key:
|
||||
webProxyAddr := tc.Config.ProxyWebHostPort()
|
||||
response, err := SSHAgentSSOLogin(webProxyAddr,
|
||||
connectorID, pub, tc.KeyTTL, tc.InsecureSkipVerify, loopbackPool(webProxyAddr), protocol)
|
||||
response, err := SSHAgentSSOLogin(
|
||||
webProxyAddr,
|
||||
connectorID,
|
||||
pub,
|
||||
tc.KeyTTL,
|
||||
tc.InsecureSkipVerify,
|
||||
loopbackPool(webProxyAddr),
|
||||
protocol,
|
||||
tc.Compatibility)
|
||||
return response, trace.Wrap(err)
|
||||
}
|
||||
|
||||
|
@ -1162,13 +1175,15 @@ func (tc *TeleportClient) u2fLogin(pub []byte) (*SSHLoginResponse, error) {
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
response, err := SSHAgentU2FLogin(httpsProxyHostPort,
|
||||
response, err := SSHAgentU2FLogin(
|
||||
httpsProxyHostPort,
|
||||
tc.Config.Username,
|
||||
password,
|
||||
pub,
|
||||
tc.KeyTTL,
|
||||
tc.InsecureSkipVerify,
|
||||
certPool)
|
||||
certPool,
|
||||
tc.Compatibility)
|
||||
|
||||
return response, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -61,10 +61,11 @@ type SSHLoginResponse struct {
|
|||
|
||||
// SSOLoginConsoleReq is used to SSO for tsh
|
||||
type SSOLoginConsoleReq struct {
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
PublicKey []byte `json:"public_key"`
|
||||
CertTTL time.Duration `json:"cert_ttl"`
|
||||
ConnectorID string `json:"connector_id"`
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
PublicKey []byte `json:"public_key"`
|
||||
CertTTL time.Duration `json:"cert_ttl"`
|
||||
ConnectorID string `json:"connector_id"`
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
// SSOLoginConsoleResponse is a response to SSO console request
|
||||
|
@ -96,6 +97,8 @@ type CreateSSHCertReq struct {
|
|||
// TTL is a desired TTL for the cert (max is still capped by server,
|
||||
// however user can shorten the time)
|
||||
TTL time.Duration `json:"ttl"`
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSSHCertWithU2FReq are passed by web client
|
||||
|
@ -112,6 +115,8 @@ type CreateSSHCertWithU2FReq struct {
|
|||
// TTL is a desired TTL for the cert (max is still capped by server,
|
||||
// however user can shorten the time)
|
||||
TTL time.Duration `json:"ttl"`
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
type sealData struct {
|
||||
|
@ -120,7 +125,7 @@ type sealData struct {
|
|||
}
|
||||
|
||||
// SSHAgentSSOLogin is used by SSH Agent (tsh) to login using OpenID connect
|
||||
func SSHAgentSSOLogin(proxyAddr, connectorID string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool, protocol string) (*SSHLoginResponse, error) {
|
||||
func SSHAgentSSOLogin(proxyAddr, connectorID string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool, protocol string, compatibility string) (*SSHLoginResponse, error) {
|
||||
clt, proxyURL, err := initClient(proxyAddr, insecure, pool)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -200,10 +205,11 @@ func SSHAgentSSOLogin(proxyAddr, connectorID string, pubKey []byte, ttl time.Dur
|
|||
u.RawQuery = query.Encode()
|
||||
|
||||
out, err := clt.PostJSON(clt.Endpoint("webapi", protocol, "login", "console"), SSOLoginConsoleReq{
|
||||
RedirectURL: u.String(),
|
||||
PublicKey: pubKey,
|
||||
CertTTL: ttl,
|
||||
ConnectorID: connectorID,
|
||||
RedirectURL: u.String(),
|
||||
PublicKey: pubKey,
|
||||
CertTTL: ttl,
|
||||
ConnectorID: connectorID,
|
||||
Compatibility: compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -315,17 +321,18 @@ func Ping(proxyAddr string, insecure bool, pool *x509.CertPool) (*PingResponse,
|
|||
// if credentials are valid
|
||||
//
|
||||
// proxyAddr must be specified as host:port
|
||||
func SSHAgentLogin(proxyAddr, user, password, otpToken string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool) (*SSHLoginResponse, error) {
|
||||
func SSHAgentLogin(proxyAddr, user, password, otpToken string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool, compatibility string) (*SSHLoginResponse, error) {
|
||||
clt, _, err := initClient(proxyAddr, insecure, pool)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
re, err := clt.PostJSON(clt.Endpoint("webapi", "ssh", "certs"), CreateSSHCertReq{
|
||||
User: user,
|
||||
Password: password,
|
||||
OTPToken: otpToken,
|
||||
PubKey: pubKey,
|
||||
TTL: ttl,
|
||||
User: user,
|
||||
Password: password,
|
||||
OTPToken: otpToken,
|
||||
PubKey: pubKey,
|
||||
TTL: ttl,
|
||||
Compatibility: compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -344,7 +351,7 @@ func SSHAgentLogin(proxyAddr, user, password, otpToken string, pubKey []byte, tt
|
|||
// If the credentials are valid, the proxy wiil return a challenge.
|
||||
// We then call the official u2f-host binary to perform the signing and pass the signature to the proxy.
|
||||
// If the authentication succeeds, we will get a temporary certificate back
|
||||
func SSHAgentU2FLogin(proxyAddr, user, password string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool) (*SSHLoginResponse, error) {
|
||||
func SSHAgentU2FLogin(proxyAddr, user, password string, pubKey []byte, ttl time.Duration, insecure bool, pool *x509.CertPool, compatibility string) (*SSHLoginResponse, error) {
|
||||
clt, _, err := initClient(proxyAddr, insecure, pool)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -414,6 +421,7 @@ func SSHAgentU2FLogin(proxyAddr, user, password string, pubKey []byte, ttl time.
|
|||
U2FSignResponse: *u2fSignResponse,
|
||||
PubKey: pubKey,
|
||||
TTL: ttl,
|
||||
Compatibility: compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
|
@ -61,6 +61,8 @@ type UserCertParams struct {
|
|||
PermitAgentForwarding bool
|
||||
// Roles is a list of roles assigned to this user
|
||||
Roles []string
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string
|
||||
}
|
||||
|
||||
// CertRoles defines certificate roles
|
||||
|
|
|
@ -285,6 +285,9 @@ type OIDCAuthRequest struct {
|
|||
// ClientRedirectURL is a URL client wants to be redirected
|
||||
// after successfull authentication
|
||||
ClientRedirectURL string `json:"client_redirect_url"`
|
||||
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
// Check returns nil if all parameters are great, err otherwise
|
||||
|
@ -341,6 +344,9 @@ type SAMLAuthRequest struct {
|
|||
// ClientRedirectURL is a URL client wants to be redirected
|
||||
// after successfull authentication
|
||||
ClientRedirectURL string `json:"client_redirect_url"`
|
||||
|
||||
// Compatibility specifies OpenSSH compatibility flags.
|
||||
Compatibility string `json:"compatibility,omitempty"`
|
||||
}
|
||||
|
||||
// Check returns nil if all parameters are great, err otherwise
|
||||
|
|
|
@ -929,7 +929,7 @@ func newUpack(username string, allowedLogins []string, a *auth.AuthServer) (*upa
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
ucert, err := a.GenerateUserCert(upub, user, allowedLogins, 0, true)
|
||||
ucert, err := a.GenerateUserCert(upub, user, allowedLogins, 0, true, teleport.CompatibilityNone)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -203,6 +203,16 @@ func SliceContainsStr(slice []string, value string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// CheckCompatibilityFlag check that the compatibility flag is valid.
|
||||
func CheckCompatibilityFlag(s string) (string, error) {
|
||||
switch s {
|
||||
case teleport.CompatibilityNone, teleport.CompatibilityOldSSH:
|
||||
return s, nil
|
||||
default:
|
||||
return teleport.CompatibilityNone, trace.BadParameter("invalid compatibility parameter: %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// HumanTimeFormatString is a human readable date formatting
|
||||
HumanTimeFormatString = "Mon Jan _2 15:04 UTC"
|
||||
|
|
|
@ -526,6 +526,7 @@ func (m *Handler) oidcLoginConsole(w http.ResponseWriter, r *http.Request, p htt
|
|||
PublicKey: req.PublicKey,
|
||||
CertTTL: req.CertTTL,
|
||||
CheckUser: true,
|
||||
Compatibility: req.Compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
|
@ -61,6 +61,7 @@ func (m *Handler) samlSSOConsole(w http.ResponseWriter, r *http.Request, p httpr
|
|||
ClientRedirectURL: req.RedirectURL,
|
||||
PublicKey: req.PublicKey,
|
||||
CertTTL: req.CertTTL,
|
||||
Compatibility: req.Compatibility,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
|
@ -325,7 +325,7 @@ func (s *sessionCache) GetCertificateWithoutOTP(c client.CreateSSHCertReq) (*cli
|
|||
}
|
||||
defer clt.Close()
|
||||
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, clt)
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, c.Compatibility, clt)
|
||||
}
|
||||
|
||||
func (s *sessionCache) GetCertificateWithOTP(c client.CreateSSHCertReq) (*client.SSHLoginResponse, error) {
|
||||
|
@ -340,11 +340,11 @@ func (s *sessionCache) GetCertificateWithOTP(c client.CreateSSHCertReq) (*client
|
|||
}
|
||||
defer clt.Close()
|
||||
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, clt)
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, c.Compatibility, clt)
|
||||
}
|
||||
|
||||
func createCertificate(user string, pubkey []byte, ttl time.Duration, clt *auth.TunClient) (*client.SSHLoginResponse, error) {
|
||||
cert, err := clt.GenerateUserCert(pubkey, user, ttl)
|
||||
func createCertificate(user string, pubkey []byte, ttl time.Duration, compatibility string, clt *auth.TunClient) (*client.SSHLoginResponse, error) {
|
||||
cert, err := clt.GenerateUserCert(pubkey, user, ttl, compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -368,12 +368,14 @@ func (s *sessionCache) GetCertificateWithU2F(c client.CreateSSHCertWithU2FReq) (
|
|||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
clt, err := auth.NewTunClient("web.session-u2f", s.authServers, c.User, method)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
defer clt.Close()
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, clt)
|
||||
|
||||
return createCertificate(c.User, c.PubKey, c.TTL, c.Compatibility, clt)
|
||||
}
|
||||
|
||||
func (s *sessionCache) GetUserInviteInfo(token string) (user string, otpQRCode []byte, err error) {
|
||||
|
|
|
@ -92,6 +92,7 @@ type AuthCommand struct {
|
|||
output string
|
||||
outputFormat string
|
||||
compatVersion string
|
||||
compatibility string
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -243,6 +244,7 @@ func Run() {
|
|||
authSign.Flag("out", "identity output").Short('o').StringVar(&cmdAuth.output)
|
||||
authSign.Flag("format", "identity format: 'file' (default) or 'dir'").Default(DefaultIdentityFormat).StringVar(&cmdAuth.outputFormat)
|
||||
authSign.Flag("ttl", "TTL (time to live) for the generated certificate").Default(fmt.Sprintf("%v", defaults.CertDuration)).DurationVar(&cmdAuth.genTTL)
|
||||
authSign.Flag("compat", "OpenSSH compatibility flag").StringVar(&cmdAuth.compatibility)
|
||||
|
||||
// operations with reverse tunnels
|
||||
reverseTunnels := app.Command("tunnels", "Operations on reverse tunnels clusters").Hidden()
|
||||
|
@ -745,7 +747,14 @@ func (a *AuthCommand) GenerateAndSignKeys(client *auth.TunClient) error {
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
cert, err := client.GenerateUserCert(publicKey, a.genUser, a.genTTL)
|
||||
|
||||
// parse compatibility parameter
|
||||
compatibility, err := utils.CheckCompatibilityFlag(a.compatibility)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
cert, err := client.GenerateUserCert(publicKey, a.genUser, a.genTTL, compatibility)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -109,6 +109,8 @@ type CLIConf struct {
|
|||
GopsAddr string
|
||||
// IdentityFile is an argument to -i flag (path to the private key+cert file)
|
||||
IdentityFile string
|
||||
// Compatibility flags, --compat, specifies OpenSSH compatibility flags.
|
||||
Compatibility string
|
||||
}
|
||||
|
||||
// Run executes TSH client. same as main() but easier to test
|
||||
|
@ -127,6 +129,7 @@ func Run(args []string, underTest bool) {
|
|||
app.Flag("cluster", "Specify the cluster to connect").Envar("TELEPORT_SITE").StringVar(&cf.SiteName)
|
||||
app.Flag("ttl", "Minutes to live for a SSH session").Int32Var(&cf.MinsToLive)
|
||||
app.Flag("identity", "Identity file").Short('i').StringVar(&cf.IdentityFile)
|
||||
app.Flag("compat", "OpenSSH compatibility flag").StringVar(&cf.Compatibility)
|
||||
|
||||
app.Flag("insecure", "Do not verify server's certificate and host name. Use only in test environments").Default("false").BoolVar(&cf.InsecureSkipVerify)
|
||||
app.Flag("namespace", "Namespace of the cluster").Default(defaults.Namespace).Hidden().StringVar(&cf.Namespace)
|
||||
|
@ -260,6 +263,7 @@ func onLogin(cf *CLIConf) {
|
|||
if err != nil {
|
||||
utils.FatalError(err)
|
||||
}
|
||||
|
||||
if _, err := tc.Login(); err != nil {
|
||||
utils.FatalError(err)
|
||||
}
|
||||
|
@ -588,6 +592,14 @@ func makeClient(cf *CLIConf, useProfileLogin bool) (tc *client.TeleportClient, e
|
|||
if !cf.NoCache {
|
||||
c.CachePolicy = &client.CachePolicy{}
|
||||
}
|
||||
|
||||
// parse compatibility parameter
|
||||
compatibility, err := utils.CheckCompatibilityFlag(cf.Compatibility)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
c.Compatibility = compatibility
|
||||
|
||||
return client.NewClient(c)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue