fix extraneous logins in tctl output

This commit is contained in:
Forrest Marshall 2020-11-17 12:42:23 -08:00 committed by Forrest Marshall
parent 20e6466525
commit d91410771e
2 changed files with 20 additions and 18 deletions

View file

@ -1060,37 +1060,39 @@ func (set RoleSet) CheckDatabaseNamesAndUsers(ttl time.Duration, overrideTTL boo
// CheckLoginDuration checks if role set can login up to given duration and // CheckLoginDuration checks if role set can login up to given duration and
// returns a combined list of allowed logins. // returns a combined list of allowed logins.
func (set RoleSet) CheckLoginDuration(ttl time.Duration) ([]string, error) { func (set RoleSet) CheckLoginDuration(ttl time.Duration) ([]string, error) {
logins := make(map[string]bool) logins, matchedTTL := set.GetLoginsForTTL(ttl)
var matchedTTL bool
for _, role := range set {
maxSessionTTL := role.GetOptions().MaxSessionTTL.Value()
if ttl <= maxSessionTTL && maxSessionTTL != 0 {
matchedTTL = true
for _, login := range role.GetLogins(Allow) {
logins[login] = true
}
}
}
if !matchedTTL { if !matchedTTL {
return nil, trace.AccessDenied("this user cannot request a certificate for %v", ttl) return nil, trace.AccessDenied("this user cannot request a certificate for %v", ttl)
} }
if len(logins) == 0 && !set.hasPossibleLogins() { if len(logins) == 0 && !set.hasPossibleLogins() {
// user was deliberately configured to have no login capability, // user was deliberately configured to have no login capability,
// but ssh certificates must contain at least one valid principal. // but ssh certificates must contain at least one valid principal.
// we add a single distinctive value which should be unique, and // we add a single distinctive value which should be unique, and
// will never be a valid unix login (due to leading '-'). // will never be a valid unix login (due to leading '-').
logins["-teleport-nologin-"+uuid.New()] = true logins = []string{"-teleport-nologin-" + uuid.New()}
} }
if len(logins) == 0 { if len(logins) == 0 {
return nil, trace.AccessDenied("this user cannot create SSH sessions, has no allowed logins") return nil, trace.AccessDenied("this user cannot create SSH sessions, has no allowed logins")
} }
out := make([]string, 0, len(logins))
for login := range logins { return logins, nil
out = append(out, login) }
// GetLoginsForTTL collects all logins that are valid for the given TTL. The matchedTTL
// value indicates whether the TTL is within scope of *any* role. This helps to distinguish
// between TTLs which are categorically invalid, and TTLs which are theoretically valid
// but happen to grant no logins.
func (set RoleSet) GetLoginsForTTL(ttl time.Duration) (logins []string, matchedTTL bool) {
for _, role := range set {
maxSessionTTL := role.GetOptions().MaxSessionTTL.Value()
if ttl <= maxSessionTTL && maxSessionTTL != 0 {
matchedTTL = true
logins = append(logins, role.GetLogins(Allow)...)
}
} }
return out, nil return utils.Deduplicate(logins), matchedTTL
} }
// CheckAccessToRemoteCluster checks if a role has access to remote cluster. Deny rules are // CheckAccessToRemoteCluster checks if a role has access to remote cluster. Deny rules are

View file

@ -576,6 +576,6 @@ func hostCAFormat(ca services.CertAuthority, keyBytes []byte, client auth.Client
if err != nil { if err != nil {
return "", trace.Wrap(err) return "", trace.Wrap(err)
} }
allowedLogins, _ := roles.CheckLoginDuration(defaults.MinCertDuration + time.Second) allowedLogins, _ := roles.GetLoginsForTTL(defaults.MinCertDuration + time.Second)
return sshutils.MarshalAuthorizedHostsFormat(ca.GetClusterName(), keyBytes, allowedLogins) return sshutils.MarshalAuthorizedHostsFormat(ca.GetClusterName(), keyBytes, allowedLogins)
} }