mirror of
https://github.com/gravitational/teleport
synced 2024-10-21 09:44:51 +00:00
Merge branch 'master' into alexey/http-headers
This commit is contained in:
commit
c156e5a4ab
|
@ -158,7 +158,7 @@ tctl create -f dev.yaml
|
|||
### Login
|
||||
|
||||
For the Web UI, if the above configuration were real, you would see a button
|
||||
that says `Login with adfs`. Simply click on that and you will be
|
||||
that says `Login with Okta`. Simply click on that and you will be
|
||||
re-directed to a login page for your identity provider and if successful,
|
||||
redirected back to Teleport.
|
||||
|
||||
|
@ -167,6 +167,10 @@ and a browser window should automatically open taking you to the login page for
|
|||
your identity provider. `tsh` will also output a link the login page of the
|
||||
identity provider if you are not automatically redirected.
|
||||
|
||||
!!! note "IMPORTANT":
|
||||
Teleport only supports sending party initiated flows for SAML 2.0. This
|
||||
means you can not initiate login from your identity provider, you have to
|
||||
initiate login from either the Teleport Web UI or CLI.
|
||||
|
||||
## ADFS
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ func (s *InstanceSecrets) GetRoles() []services.Role {
|
|||
continue
|
||||
}
|
||||
role := services.RoleForCertAuthority(ca)
|
||||
role.SetLogins(s.AllowedLogins())
|
||||
role.SetLogins(services.Allow, s.AllowedLogins())
|
||||
roles = append(roles, role)
|
||||
}
|
||||
return roles
|
||||
|
@ -301,7 +301,7 @@ func (i *TeleInstance) CreateEx(trustedSecrets []*InstanceSecrets, tconf *servic
|
|||
var roles []services.Role
|
||||
if len(user.Roles) == 0 {
|
||||
role := services.RoleForUser(teleUser)
|
||||
role.SetLogins(user.AllowedLogins)
|
||||
role.SetLogins(services.Allow, user.AllowedLogins)
|
||||
err = auth.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
|
@ -333,7 +333,7 @@ func (i *TeleInstance) CreateEx(trustedSecrets []*InstanceSecrets, tconf *servic
|
|||
}
|
||||
// sign user's keys:
|
||||
ttl := 24 * time.Hour
|
||||
logins, err := services.RoleSet(roles).CheckLogins(ttl)
|
||||
logins, err := services.RoleSet(roles).CheckLoginDuration(ttl)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -678,8 +678,10 @@ func (s *IntSuite) TestMapRoles(c *check.C) {
|
|||
|
||||
// main cluster has a local user and belongs to role "main-devs"
|
||||
mainDevs := "main-devs"
|
||||
role, err := services.NewRole(mainDevs, services.RoleSpecV2{
|
||||
Logins: []string{username},
|
||||
role, err := services.NewRole(mainDevs, services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Logins: []string{username},
|
||||
},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
main.AddUserWithRole(username, role)
|
||||
|
@ -704,8 +706,10 @@ func (s *IntSuite) TestMapRoles(c *check.C) {
|
|||
// using trusted clusters, so remote user will be allowed to assume
|
||||
// role specified by mapping remote role "devs" to local role "local-devs"
|
||||
auxDevs := "aux-devs"
|
||||
role, err = services.NewRole(auxDevs, services.RoleSpecV2{
|
||||
Logins: []string{username},
|
||||
role, err = services.NewRole(auxDevs, services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Logins: []string{username},
|
||||
},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
err = aux.Process.GetAuthServer().UpsertRole(role, backend.Forever)
|
||||
|
|
|
@ -129,7 +129,7 @@ func createUserAndRole(clt clt, username string, allowedLogins []string) (servic
|
|||
panic(err)
|
||||
}
|
||||
role := services.RoleForUser(user)
|
||||
role.SetLogins([]string{user.GetName()})
|
||||
role.SetLogins(services.Allow, []string{user.GetName()})
|
||||
err = clt.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -147,24 +147,28 @@ func createUserAndRoleWithoutRoles(clt clt, username string, allowedLogins []str
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
role := services.RoleForUser(user)
|
||||
role.RemoveResource(services.KindRole)
|
||||
role.SetLogins([]string{user.GetName()})
|
||||
resources := role.GetSystemResources(services.Allow)
|
||||
delete(resources, services.KindRole)
|
||||
role.SetSystemResources(services.Allow, resources)
|
||||
role.SetLogins(services.Allow, []string{user.GetName()})
|
||||
err = clt.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
user.AddRole(role.GetName())
|
||||
err = clt.UpsertUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return user, role
|
||||
}
|
||||
|
||||
// TestOwnRole tests that user can read roles assigned to them
|
||||
func (s *APISuite) TestReadOwnRole(c *C) {
|
||||
|
||||
user1, userRole := createUserAndRoleWithoutRoles(s.clt, "user1", []string{"user1"})
|
||||
user2, _ := createUserAndRoleWithoutRoles(s.clt, "user2", []string{"user2"})
|
||||
err := s.clt.UpsertPassword(user1.GetName(), []byte("abc1231"))
|
||||
|
@ -269,7 +273,9 @@ func (s *APISuite) TestGenerateKeysAndCerts(c *C) {
|
|||
c.Assert(exists, Equals, false)
|
||||
|
||||
// now update role to permit agent forwarding
|
||||
userRole.SetForwardAgent(true)
|
||||
roleOptions := userRole.GetOptions()
|
||||
roleOptions.Set(services.ForwardAgent, true)
|
||||
userRole.SetOptions(roleOptions)
|
||||
err = s.clt.UpsertRole(userRole, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
|
|
|
@ -653,7 +653,7 @@ func (s *AuthServer) NewWebSession(userName string) (services.WebSession, error)
|
|||
sessionTTL := roles.AdjustSessionTTL(defaults.CertDuration)
|
||||
bearerTokenTTL := utils.MinTTL(sessionTTL, BearerTokenTTL)
|
||||
|
||||
allowedLogins, err := roles.CheckLogins(sessionTTL)
|
||||
allowedLogins, err := roles.CheckLoginDuration(sessionTTL)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ type AuthWithRoles struct {
|
|||
}
|
||||
|
||||
func (a *AuthWithRoles) action(namespace string, resourceKind, action string) error {
|
||||
return a.checker.CheckResourceAction(namespace, resourceKind, action)
|
||||
return a.checker.CheckAccessToRuleOrResource(namespace, resourceKind, action)
|
||||
}
|
||||
|
||||
// currentUserAction is a special checker that allows certain actions for users
|
||||
|
@ -52,7 +52,7 @@ func (a *AuthWithRoles) currentUserAction(username string) error {
|
|||
if username == a.user.GetName() {
|
||||
return nil
|
||||
}
|
||||
return a.checker.CheckResourceAction(
|
||||
return a.checker.CheckAccessToRuleOrResource(
|
||||
defaults.Namespace, services.KindUser, services.ActionWrite)
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ func (a *AuthWithRoles) GenerateUserCert(key []byte, username string, ttl time.D
|
|||
sessionTTL := checker.AdjustSessionTTL(ttl)
|
||||
|
||||
// check signing TTL and return a list of allowed logins
|
||||
allowedLogins, err := checker.CheckLogins(sessionTTL)
|
||||
allowedLogins, err := checker.CheckLoginDuration(sessionTTL)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -310,6 +310,11 @@ func migrateLegacyResources(cfg InitConfig, asrv *AuthServer) error {
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = migrateRoles(asrv)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -329,7 +334,7 @@ func migrateUsers(asrv *AuthServer) error {
|
|||
|
||||
// create role for user and upsert to backend
|
||||
role := services.RoleForUser(user)
|
||||
role.SetLogins(raw.AllowedLogins)
|
||||
role.SetLogins(services.Allow, raw.AllowedLogins)
|
||||
err = asrv.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
|
@ -418,6 +423,31 @@ func migrateAuthPreference(cfg InitConfig, asrv *AuthServer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func migrateRoles(asrv *AuthServer) error {
|
||||
roles, err := asrv.GetRoles()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// loop over all roles and only migrate RoleV2 -> RoleV3
|
||||
for i, _ := range roles {
|
||||
role := roles[i]
|
||||
_, ok := (role.GetRawObject()).(services.RoleV2)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// with RoleV2 we never had a TTL so upsert them forever
|
||||
err = asrv.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Infof("[MIGRATION] Updated Role: %v", role.GetName())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isFirstStart returns 'true' if the auth server is starting for the 1st time
|
||||
// on this server.
|
||||
func isFirstStart(authServer *AuthServer, cfg InitConfig) (bool, error) {
|
||||
|
|
|
@ -197,7 +197,7 @@ func (s *AuthServer) CreateUserWithOTP(token string, password string, otpToken s
|
|||
|
||||
// apply user allowed logins
|
||||
role := services.RoleForUser(tokenData.User.V2())
|
||||
role.SetLogins(tokenData.User.AllowedLogins)
|
||||
role.SetLogins(services.Allow, tokenData.User.AllowedLogins)
|
||||
if err := s.UpsertRole(role, backend.Forever); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ func (s *AuthServer) CreateUserWithoutOTP(token string, password string) (servic
|
|||
|
||||
// apply user allowed logins
|
||||
role := services.RoleForUser(tokenData.User.V2())
|
||||
role.SetLogins(tokenData.User.AllowedLogins)
|
||||
role.SetLogins(services.Allow, tokenData.User.AllowedLogins)
|
||||
if err := s.UpsertRole(role, backend.Forever); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ func (s *AuthServer) CreateUserWithU2FToken(token string, password string, respo
|
|||
}
|
||||
|
||||
role := services.RoleForUser(tokenData.User.V2())
|
||||
role.SetLogins(tokenData.User.AllowedLogins)
|
||||
role.SetLogins(services.Allow, tokenData.User.AllowedLogins)
|
||||
if err := s.UpsertRole(role, backend.Forever); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ func (a *AuthServer) ValidateOIDCAuthCallback(q url.Values) (*OIDCAuthResponse,
|
|||
|
||||
if len(req.PublicKey) != 0 {
|
||||
certTTL := utils.MinTTL(utils.ToTTL(a.clock, ident.ExpiresAt), req.CertTTL)
|
||||
allowedLogins, err := roles.CheckLogins(certTTL)
|
||||
allowedLogins, err := roles.CheckLoginDuration(certTTL)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -149,97 +149,114 @@ func GetCheckerForBuiltinRole(role teleport.Role) (services.AccessChecker, error
|
|||
case teleport.RoleAuth:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.KindAuthServer: services.RW()},
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.KindAuthServer: services.RW(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleProvisionToken:
|
||||
return services.FromSpec(role.String(), services.RoleSpecV2{})
|
||||
return services.FromSpec(role.String(), services.RoleSpecV3{})
|
||||
case teleport.RoleNode:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.KindNode: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindEvent: services.RW(),
|
||||
services.KindProxy: services.RO(),
|
||||
services.KindCertAuthority: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.KindNode: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindEvent: services.RW(),
|
||||
services.KindProxy: services.RO(),
|
||||
services.KindCertAuthority: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleProxy:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.KindProxy: services.RW(),
|
||||
services.KindOIDCRequest: services.RW(),
|
||||
services.KindOIDC: services.RO(),
|
||||
services.KindSAMLRequest: services.RW(),
|
||||
services.KindSAML: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindEvent: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindNode: services.RO(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindReverseTunnel: services.RO(),
|
||||
services.KindCertAuthority: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindClusterAuthPreference: services.RO(),
|
||||
services.KindUniversalSecondFactor: services.RO(),
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.KindProxy: services.RW(),
|
||||
services.KindOIDCRequest: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindEvent: services.RW(),
|
||||
services.KindSAMLRequest: services.RW(),
|
||||
services.KindOIDC: services.RO(),
|
||||
services.KindSAML: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindNode: services.RO(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindReverseTunnel: services.RO(),
|
||||
services.KindCertAuthority: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindClusterAuthPreference: services.RO(),
|
||||
services.KindUniversalSecondFactor: services.RO(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleWeb:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.KindWebSession: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindTrustedCluster: services.RO(),
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.KindWebSession: services.RW(),
|
||||
services.KindSession: services.RW(),
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindUser: services.RO(),
|
||||
services.KindRole: services.RO(),
|
||||
services.KindNamespace: services.RO(),
|
||||
services.KindTrustedCluster: services.RO(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleSignup:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindClusterAuthPreference: services.RO(),
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.KindAuthServer: services.RO(),
|
||||
services.KindClusterAuthPreference: services.RO(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleAdmin:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
MaxSessionTTL: services.MaxDuration(),
|
||||
Logins: []string{},
|
||||
Namespaces: []string{services.Wildcard},
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
Resources: map[string][]string{
|
||||
services.Wildcard: services.RW(),
|
||||
services.RoleSpecV3{
|
||||
Options: services.RoleOptions{
|
||||
services.MaxSessionTTL: services.MaxDuration(),
|
||||
},
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{services.Wildcard},
|
||||
Logins: []string{},
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
SystemResources: map[string][]string{
|
||||
services.Wildcard: services.RW(),
|
||||
},
|
||||
},
|
||||
})
|
||||
case teleport.RoleNop:
|
||||
return services.FromSpec(
|
||||
role.String(),
|
||||
services.RoleSpecV2{
|
||||
Namespaces: []string{},
|
||||
Resources: map[string][]string{},
|
||||
services.RoleSpecV3{
|
||||
Allow: services.RoleConditions{
|
||||
Namespaces: []string{},
|
||||
SystemResources: map[string][]string{},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -189,9 +189,14 @@ func parseSAMLInResponseTo(response string) (string, error) {
|
|||
return "", trace.BadParameter("unable to parse response")
|
||||
}
|
||||
|
||||
// teleport only supports sending party initiated flows (Teleport sends an
|
||||
// AuthnRequest to the IdP and gets a SAMLResponse from the IdP). identity
|
||||
// provider initiated flows (where Teleport gets an unsolicited SAMLResponse
|
||||
// from the IdP) are not supported.
|
||||
el := doc.Root()
|
||||
responseTo := el.SelectAttr("InResponseTo")
|
||||
if responseTo == nil {
|
||||
log.Errorf("[SAML] Teleport does not support initiating login from an identity provider, login must be initiated from either the Teleport Web UI or CLI.")
|
||||
return "", trace.BadParameter("identity provider initiated flows are not supported")
|
||||
}
|
||||
if responseTo.Value == "" {
|
||||
|
@ -311,7 +316,7 @@ func (a *AuthServer) ValidateSAMLResponse(samlResponse string) (*SAMLAuthRespons
|
|||
|
||||
if len(request.PublicKey) != 0 {
|
||||
certTTL := utils.MinTTL(utils.ToTTL(a.clock, expiresAt), request.CertTTL)
|
||||
allowedLogins, err := roles.CheckLogins(certTTL)
|
||||
allowedLogins, err := roles.CheckLoginDuration(certTTL)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -138,7 +138,9 @@ func (s *TunSuite) TestUnixServerClient(c *C) {
|
|||
otpSecret := base32.StdEncoding.EncodeToString([]byte(rawSecret))
|
||||
|
||||
user, role := createUserAndRole(s.a, userName, []string{userName})
|
||||
role.SetResource(services.KindNode, services.RW())
|
||||
resources := role.GetSystemResources(services.Allow)
|
||||
resources[services.KindNode] = services.RW()
|
||||
role.SetSystemResources(services.Allow, resources)
|
||||
err = s.a.UpsertRole(role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
|
|
|
@ -474,7 +474,7 @@ func parseAuthorizedKeys(bytes []byte, allowedLogins []string) (services.CertAut
|
|||
|
||||
// transform old allowed logins into roles
|
||||
role := services.RoleForCertAuthority(ca)
|
||||
role.SetLogins(allowedLogins)
|
||||
role.SetLogins(services.Allow, allowedLogins)
|
||||
ca.AddRole(role.GetName())
|
||||
|
||||
return ca, role, nil
|
||||
|
|
|
@ -171,7 +171,7 @@ func GetAuthPreferenceSchema(extensionSchema string) string {
|
|||
} else {
|
||||
authPreferenceSchema = fmt.Sprintf(AuthPreferenceSpecSchemaTemplate, ","+extensionSchema)
|
||||
}
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, authPreferenceSchema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, authPreferenceSchema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
// AuthPreferenceMarshaler implements marshal/unmarshal of AuthPreference implementations
|
||||
|
|
|
@ -542,7 +542,7 @@ type CertAuthorityMarshaler interface {
|
|||
|
||||
// GetCertAuthoritySchema returns JSON Schema for cert authorities
|
||||
func GetCertAuthoritySchema() string {
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, fmt.Sprintf(CertAuthoritySpecV2Schema, RoleMapSchema))
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, fmt.Sprintf(CertAuthoritySpecV2Schema, RoleMapSchema), DefaultDefinitions)
|
||||
}
|
||||
|
||||
type TeleportCertAuthorityMarshaler struct{}
|
||||
|
|
|
@ -382,7 +382,7 @@ func GetTrustedClusterSchema(extensionSchema string) string {
|
|||
} else {
|
||||
trustedClusterSchema = fmt.Sprintf(TrustedClusterSpecSchemaTemplate, RoleMapSchema, ","+extensionSchema)
|
||||
}
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, trustedClusterSchema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, trustedClusterSchema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
// TrustedClusterMarshaler implements marshal/unmarshal of TrustedCluster implementations
|
||||
|
|
|
@ -240,3 +240,61 @@ func (s *MigrationsSuite) TestMigrateCertAuthorities(c *C) {
|
|||
in.AllowedLogins = nil
|
||||
c.Assert(out3, DeepEquals, *in)
|
||||
}
|
||||
|
||||
func (s *MigrationsSuite) TestMigrateRoles(c *C) {
|
||||
in := &RoleV2{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
MaxSessionTTL: NewDuration(20 * time.Hour),
|
||||
Logins: []string{"foo"},
|
||||
NodeLabels: map[string]string{"a": "b"},
|
||||
Namespaces: []string{"system", "default"},
|
||||
Resources: map[string][]string{"role": []string{"read", "write"}},
|
||||
},
|
||||
}
|
||||
|
||||
out := in.V3()
|
||||
expected := &RoleV3{
|
||||
Kind: KindRole,
|
||||
Version: V3,
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV3{
|
||||
Options: RoleOptions{
|
||||
MaxSessionTTL: NewDuration(20 * time.Hour),
|
||||
},
|
||||
Allow: RoleConditions{
|
||||
Logins: []string{"foo"},
|
||||
NodeLabels: map[string]string{"a": "b"},
|
||||
Namespaces: []string{"system", "default"},
|
||||
SystemResources: map[string][]string{
|
||||
"role": []string{ActionRead, ActionWrite},
|
||||
},
|
||||
},
|
||||
},
|
||||
rawObject: *in,
|
||||
}
|
||||
c.Assert(out.rawObject, DeepEquals, *in)
|
||||
c.Assert(out, DeepEquals, expected)
|
||||
|
||||
data, err := json.Marshal(in)
|
||||
c.Assert(err, IsNil)
|
||||
out2, err := GetRoleMarshaler().UnmarshalRole(data)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(out2, DeepEquals, out)
|
||||
|
||||
// check V3 marshaling
|
||||
data, err = GetRoleMarshaler().MarshalRole(expected)
|
||||
c.Assert(err, IsNil)
|
||||
out3, err := GetRoleMarshaler().UnmarshalRole(data)
|
||||
c.Assert(err, IsNil)
|
||||
expected.rawObject = nil
|
||||
c.Assert(out3, DeepEquals, expected)
|
||||
}
|
||||
|
|
|
@ -451,7 +451,7 @@ func (o *OIDCConnectorV2) RoleFromTemplate(claims jose.Claims) (Role, error) {
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return roleTemplate, nil
|
||||
return roleTemplate.V3(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ var ClaimMappingSchema = fmt.Sprintf(`{
|
|||
},
|
||||
"role_template": %v
|
||||
}
|
||||
}`, GetRoleSchema(""))
|
||||
}`, GetRoleSchema(V2, ""))
|
||||
|
||||
// OIDCConnectorV1 specifies configuration for Open ID Connect compatible external
|
||||
// identity provider, e.g. google in some organisation
|
||||
|
|
|
@ -17,12 +17,9 @@ package services
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
|
@ -74,46 +71,14 @@ func (s *OIDCSuite) TestUnmarshal(c *check.C) {
|
|||
}
|
||||
`
|
||||
|
||||
output := OIDCConnectorV2{
|
||||
Kind: KindOIDCConnector,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: "google",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: OIDCConnectorSpecV2{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "id-from-google.apps.googleusercontent.com",
|
||||
ClientSecret: "secret-key-from-google",
|
||||
RedirectURL: "https://localhost:3080/v1/webapi/oidc/callback",
|
||||
Display: "whatever",
|
||||
Scope: []string{"roles"},
|
||||
ClaimsToRoles: []ClaimMapping{
|
||||
ClaimMapping{
|
||||
Claim: "roles",
|
||||
Value: "teleport-user",
|
||||
RoleTemplate: &RoleV2{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: `{{index . "email"}}`,
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
Namespaces: []string{"default"},
|
||||
MaxSessionTTL: NewDuration(90 * 60 * time.Minute),
|
||||
Logins: []string{`{{index . "nickname"}}`, `root`},
|
||||
NodeLabels: map[string]string{"*": "*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
oc, err := GetOIDCConnectorMarshaler().UnmarshalOIDCConnector([]byte(input))
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(oc, check.DeepEquals, &output)
|
||||
|
||||
c.Assert(oc.GetName(), check.Equals, "google")
|
||||
c.Assert(oc.GetIssuerURL(), check.Equals, "https://accounts.google.com")
|
||||
c.Assert(oc.GetClientID(), check.Equals, "id-from-google.apps.googleusercontent.com")
|
||||
c.Assert(oc.GetRedirectURL(), check.Equals, "https://localhost:3080/v1/webapi/oidc/callback")
|
||||
c.Assert(oc.GetDisplay(), check.Equals, "whatever")
|
||||
}
|
||||
|
||||
func (s *OIDCSuite) TestUnmarshalInvalid(c *check.C) {
|
||||
|
@ -161,64 +126,3 @@ func (s *OIDCSuite) TestUnmarshalInvalid(c *check.C) {
|
|||
err = oc.Check()
|
||||
c.Assert(err, check.NotNil)
|
||||
}
|
||||
|
||||
// TestRoleFromTemplate checks that we can create a valid role from a template. Also
|
||||
// makes sure missing fields are filled in.
|
||||
func (s *OIDCSuite) TestRoleFromTemplate(c *check.C) {
|
||||
oidcConnector := OIDCConnectorV2{
|
||||
Kind: KindOIDCConnector,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: "google",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: OIDCConnectorSpecV2{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "id-from-google.apps.googleusercontent.com",
|
||||
ClientSecret: "secret-key-from-google",
|
||||
RedirectURL: "https://localhost:3080/v1/webapi/oidc/callback",
|
||||
Display: "whatever",
|
||||
Scope: []string{"roles"},
|
||||
ClaimsToRoles: []ClaimMapping{
|
||||
ClaimMapping{
|
||||
Claim: "roles",
|
||||
Value: "teleport-user",
|
||||
RoleTemplate: &RoleV2{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: `{{index . "email"}}`,
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
MaxSessionTTL: NewDuration(30 * 60 * time.Minute),
|
||||
Logins: []string{`{{index . "nickname"}}`, `root`},
|
||||
NodeLabels: map[string]string{"*": "*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// create some claims
|
||||
var claims = make(jose.Claims)
|
||||
claims.Add("roles", "teleport-user")
|
||||
claims.Add("email", "foo@example.com")
|
||||
claims.Add("nickname", "foo")
|
||||
claims.Add("full_name", "foo bar")
|
||||
|
||||
role, err := oidcConnector.RoleFromTemplate(claims)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
outRole, err := NewRole("foo@example.com", RoleSpecV2{
|
||||
Logins: []string{"foo", "root"},
|
||||
MaxSessionTTL: NewDuration(30 * time.Hour),
|
||||
NodeLabels: map[string]string{"*": "*"},
|
||||
Namespaces: []string{"default"},
|
||||
Resources: nil,
|
||||
ForwardAgent: false,
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(role, check.DeepEquals, outRole)
|
||||
}
|
||||
|
|
|
@ -118,11 +118,14 @@ const (
|
|||
// KindTrustedCluster is a resource that contains trusted cluster configuration.
|
||||
KindTrustedCluster = "trusted_cluster"
|
||||
|
||||
// V2 is our current version
|
||||
// V3 is the third version of resources.
|
||||
V3 = "v3"
|
||||
|
||||
// V2 is the second version of resources.
|
||||
V2 = "v2"
|
||||
|
||||
// V1 is our first version
|
||||
// resources were not explicitly versioned at that point
|
||||
// V1 is the first version of resources. Note: The first version was
|
||||
// not explicitly versioned.
|
||||
V1 = "v1"
|
||||
)
|
||||
|
||||
|
@ -179,7 +182,7 @@ const V2SchemaTemplate = `{
|
|||
"version": {"type": "string", "default": "v2"},
|
||||
"metadata": %v,
|
||||
"spec": %v
|
||||
}
|
||||
}%v
|
||||
}`
|
||||
|
||||
// MetadataSchema is a schema for resource metadata
|
||||
|
@ -202,6 +205,9 @@ const MetadataSchema = `{
|
|||
}
|
||||
}`
|
||||
|
||||
// DefaultDefinitions the default list of JSON schema definitions which is none.
|
||||
const DefaultDefinitions = ``
|
||||
|
||||
// UnknownResource is used to detect resources
|
||||
type UnknownResource struct {
|
||||
ResourceHeader
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,7 @@ package services
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -34,6 +35,7 @@ type RoleSuite struct {
|
|||
}
|
||||
|
||||
var _ = Suite(&RoleSuite{})
|
||||
var _ = fmt.Printf
|
||||
|
||||
func (s *RoleSuite) SetUpSuite(c *C) {
|
||||
utils.InitLoggerForTests()
|
||||
|
@ -49,104 +51,103 @@ func (s *RoleSuite) TestRoleExtension(c *C) {
|
|||
}
|
||||
in := `{"kind": "role", "metadata": {"name": "name1"}, "spec": {"a": "b"}}`
|
||||
var role ExtendedRole
|
||||
err := utils.UnmarshalWithSchema(GetRoleSchema(`"a": {"type": "string"}`), &role, []byte(in))
|
||||
err := utils.UnmarshalWithSchema(GetRoleSchema(V2, `"a": {"type": "string"}`), &role, []byte(in))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(role.Spec.A, Equals, "b")
|
||||
|
||||
// this is a bad type
|
||||
in = `{"kind": "role", "metadata": {"name": "name1"}, "spec": {"a": 12}}`
|
||||
err = utils.UnmarshalWithSchema(GetRoleSchema(`"a": {"type": "string"}`), &role, []byte(in))
|
||||
err = utils.UnmarshalWithSchema(GetRoleSchema(V2, `"a": {"type": "string"}`), &role, []byte(in))
|
||||
c.Assert(err, NotNil)
|
||||
}
|
||||
|
||||
func (s *RoleSuite) TestRoleParse(c *C) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
role RoleV2
|
||||
role RoleV3
|
||||
error error
|
||||
}{
|
||||
// 0 - no input, should not parse
|
||||
{
|
||||
in: ``,
|
||||
error: trace.BadParameter("empty input"),
|
||||
},
|
||||
// 1 - validation error, no name
|
||||
{
|
||||
in: `{}`,
|
||||
error: trace.BadParameter("failed to validate: name: name is required"),
|
||||
},
|
||||
// 2 - validation error, no name
|
||||
{
|
||||
in: `{"kind": "role"}`,
|
||||
error: trace.BadParameter("failed to validate: name: name is required"),
|
||||
},
|
||||
// 3 - role with no spec
|
||||
{
|
||||
in: `{"kind": "role", "metadata": {"name": "name1"}, "spec": {}}`,
|
||||
role: RoleV2{
|
||||
in: `{"kind": "role", "version": "v3", "metadata": {"name": "name1"}, "spec": {}}`,
|
||||
role: RoleV3{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Version: V3,
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{},
|
||||
Spec: RoleSpecV3{},
|
||||
},
|
||||
},
|
||||
// 4 - full valid role
|
||||
{
|
||||
in: `{
|
||||
"kind": "role",
|
||||
"metadata": {"name": "name1"},
|
||||
"spec": {
|
||||
"max_session_ttl": "20h",
|
||||
"node_labels": {"a": "b"},
|
||||
"namespaces": ["system", "default"],
|
||||
"resources": {
|
||||
"role": ["read", "write"]
|
||||
"kind": "role",
|
||||
"version": "v3",
|
||||
"metadata": {"name": "name1"},
|
||||
"spec": {
|
||||
"options": {
|
||||
"max_session_ttl": "20h"
|
||||
},
|
||||
"allow": {
|
||||
"node_labels": {"a": "b"},
|
||||
"namespaces": ["system", "default"],
|
||||
"rules": [
|
||||
{
|
||||
"resources": ["role"],
|
||||
"verbs": ["read", "write"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"deny": {
|
||||
"logins": ["c"]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
role: RoleV2{
|
||||
}
|
||||
}`,
|
||||
role: RoleV3{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Version: V3,
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
MaxSessionTTL: Duration{20 * time.Hour},
|
||||
NodeLabels: map[string]string{"a": "b"},
|
||||
Namespaces: []string{"system", "default"},
|
||||
Resources: map[string][]string{"role": {ActionRead, ActionWrite}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: `kind: role
|
||||
metadata:
|
||||
name: name1
|
||||
spec:
|
||||
max_session_ttl: 20h
|
||||
node_labels:
|
||||
a: b
|
||||
namespaces: ["system", "default"]
|
||||
resources:
|
||||
role: [read, write]
|
||||
`,
|
||||
role: RoleV2{
|
||||
Kind: KindRole,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
MaxSessionTTL: Duration{20 * time.Hour},
|
||||
NodeLabels: map[string]string{"a": "b"},
|
||||
Namespaces: []string{"system", "default"},
|
||||
Resources: map[string][]string{"role": {ActionRead, ActionWrite}},
|
||||
Spec: RoleSpecV3{
|
||||
Options: RoleOptions{
|
||||
MaxSessionTTL: NewDuration(20 * time.Hour),
|
||||
},
|
||||
Allow: RoleConditions{
|
||||
NodeLabels: map[string]string{"a": "b"},
|
||||
Namespaces: []string{"system", "default"},
|
||||
Rules: map[string][]string{
|
||||
"role": []string{ActionRead, ActionWrite},
|
||||
},
|
||||
},
|
||||
Deny: RoleConditions{
|
||||
Logins: []string{"c"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
comment := Commentf("test case %v", i)
|
||||
|
||||
role, err := UnmarshalRole([]byte(tc.in))
|
||||
if tc.error != nil {
|
||||
c.Assert(err, NotNil, comment)
|
||||
|
@ -154,7 +155,7 @@ spec:
|
|||
c.Assert(err, IsNil, comment)
|
||||
c.Assert(*role, DeepEquals, tc.role, comment)
|
||||
|
||||
out, err := json.Marshal(*role)
|
||||
out, err := json.Marshal(role)
|
||||
c.Assert(err, IsNil, comment)
|
||||
|
||||
role2, err := UnmarshalRole(out)
|
||||
|
@ -296,7 +297,7 @@ func (s *RoleSuite) TestCheckAccess(c *C) {
|
|||
|
||||
var set RoleSet
|
||||
for i := range tc.roles {
|
||||
set = append(set, &tc.roles[i])
|
||||
set = append(set, tc.roles[i].V3())
|
||||
}
|
||||
for j, check := range tc.checks {
|
||||
comment := Commentf("test case %v '%v', check %v", i, tc.name, j)
|
||||
|
@ -320,27 +321,31 @@ func (s *RoleSuite) TestCheckResourceAccess(c *C) {
|
|||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
roles []RoleV2
|
||||
roles []RoleV3
|
||||
checks []check
|
||||
}{
|
||||
{
|
||||
name: "empty role set has access to nothing",
|
||||
roles: []RoleV2{},
|
||||
name: "0 - empty role set has access to nothing",
|
||||
roles: []RoleV3{},
|
||||
checks: []check{
|
||||
{resource: KindUser, action: ActionWrite, namespace: defaults.Namespace, hasAccess: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user can read sessions in default namespace",
|
||||
roles: []RoleV2{
|
||||
RoleV2{
|
||||
name: "1 - user can read sessions in default namespace",
|
||||
roles: []RoleV3{
|
||||
RoleV3{
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Resources: map[string][]string{KindSession: []string{ActionRead}},
|
||||
Spec: RoleSpecV3{
|
||||
Allow: RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
SystemResources: map[string][]string{
|
||||
KindSession: []string{ActionRead},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -350,26 +355,34 @@ func (s *RoleSuite) TestCheckResourceAccess(c *C) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "user can read sessions in system namespace and write stuff in default namespace",
|
||||
roles: []RoleV2{
|
||||
RoleV2{
|
||||
name: "1 - user can read sessions in system namespace and write stuff in default namespace",
|
||||
roles: []RoleV3{
|
||||
RoleV3{
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
Namespaces: []string{"system"},
|
||||
Resources: map[string][]string{KindSession: []string{ActionRead}},
|
||||
Spec: RoleSpecV3{
|
||||
Allow: RoleConditions{
|
||||
Namespaces: []string{"system"},
|
||||
SystemResources: map[string][]string{
|
||||
KindSession: []string{ActionRead},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RoleV2{
|
||||
RoleV3{
|
||||
Metadata: Metadata{
|
||||
Name: "name2",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV2{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Resources: map[string][]string{KindSession: []string{ActionWrite, ActionRead}},
|
||||
Spec: RoleSpecV3{
|
||||
Allow: RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
SystemResources: map[string][]string{
|
||||
KindSession: []string{ActionWrite, ActionRead},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -380,16 +393,68 @@ func (s *RoleSuite) TestCheckResourceAccess(c *C) {
|
|||
{resource: KindRole, action: ActionRead, namespace: defaults.Namespace, hasAccess: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "3 - deny rules override allow rules",
|
||||
roles: []RoleV3{
|
||||
RoleV3{
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV3{
|
||||
Deny: RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Rules: map[string][]string{
|
||||
KindSession: []string{ActionWrite},
|
||||
},
|
||||
},
|
||||
Allow: RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Rules: map[string][]string{
|
||||
KindSession: []string{ActionWrite},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
checks: []check{
|
||||
{resource: KindSession, action: ActionWrite, namespace: defaults.Namespace, hasAccess: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "4 - rules override system resources",
|
||||
roles: []RoleV3{
|
||||
RoleV3{
|
||||
Metadata: Metadata{
|
||||
Name: "name1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: RoleSpecV3{
|
||||
Allow: RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Rules: map[string][]string{
|
||||
KindSession: []string{ActionWrite},
|
||||
},
|
||||
SystemResources: map[string][]string{
|
||||
KindSession: []string{ActionRead},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
checks: []check{
|
||||
{resource: KindSession, action: ActionWrite, namespace: defaults.Namespace, hasAccess: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
|
||||
var set RoleSet
|
||||
for i := range tc.roles {
|
||||
set = append(set, &tc.roles[i])
|
||||
}
|
||||
for j, check := range tc.checks {
|
||||
comment := Commentf("test case %v '%v', check %v", i, tc.name, j)
|
||||
result := set.CheckResourceAction(check.namespace, check.resource, check.action)
|
||||
result := set.CheckAccessToRuleOrResource(check.namespace, check.resource, check.action)
|
||||
if check.hasAccess {
|
||||
c.Assert(result, IsNil, comment)
|
||||
} else {
|
||||
|
|
|
@ -320,7 +320,7 @@ func (o *SAMLConnectorV2) Equals(other SAMLConnector) bool {
|
|||
if (a.RoleTemplate != nil && b.RoleTemplate == nil) || (a.RoleTemplate == nil && b.RoleTemplate != nil) {
|
||||
return false
|
||||
}
|
||||
if a.RoleTemplate != nil && !a.RoleTemplate.Equals(b.RoleTemplate) {
|
||||
if a.RoleTemplate != nil && !a.RoleTemplate.Equals(b.RoleTemplate.V3()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ func (o *SAMLConnectorV2) RoleFromTemplate(assertionInfo saml2.AssertionInfo) (R
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return roleTemplate, nil
|
||||
return roleTemplate.V3(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -788,7 +788,7 @@ var AttributeMappingSchema = fmt.Sprintf(`{
|
|||
},
|
||||
"role_template": %v
|
||||
}
|
||||
}`, GetRoleSchema(""))
|
||||
}`, GetRoleSchema(V2, ""))
|
||||
|
||||
// SigningKeyPairSchema
|
||||
var SigningKeyPairSchema = `{
|
||||
|
|
|
@ -411,7 +411,7 @@ func (c *CommandLabels) SetEnv(v string) error {
|
|||
// GetServerSchema returns role schema with optionally injected
|
||||
// schema for extensions
|
||||
func GetServerSchema() string {
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ServerSpecV2Schema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ServerSpecV2Schema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
// UnmarshalServerResource unmarshals role from JSON or YAML,
|
||||
|
|
|
@ -348,7 +348,7 @@ func GetWebSessionSchema() string {
|
|||
|
||||
// GetWebSessionSchemaWithExtensions returns JSON Schema for web session with user-supplied extensions
|
||||
func GetWebSessionSchemaWithExtensions(extension string) string {
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, fmt.Sprintf(WebSessionSpecV2Schema, extension))
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, fmt.Sprintf(WebSessionSpecV2Schema, extension), DefaultDefinitions)
|
||||
}
|
||||
|
||||
type TeleportWebSessionMarshaler struct{}
|
||||
|
|
|
@ -378,19 +378,25 @@ func (s *ServicesTestSuite) RolesCRUD(c *C) {
|
|||
c.Assert(err, IsNil)
|
||||
c.Assert(len(out), Equals, 0)
|
||||
|
||||
role := services.RoleV2{
|
||||
role := services.RoleV3{
|
||||
Kind: services.KindRole,
|
||||
Version: services.V2,
|
||||
Version: services.V3,
|
||||
Metadata: services.Metadata{
|
||||
Name: "role1",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: services.RoleSpecV2{
|
||||
Logins: []string{"root", "bob"},
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
MaxSessionTTL: services.Duration{Duration: time.Hour},
|
||||
Namespaces: []string{"default", "system"},
|
||||
Resources: map[string][]string{services.KindRole: []string{services.ActionRead}},
|
||||
Spec: services.RoleSpecV3{
|
||||
Options: services.RoleOptions{
|
||||
services.MaxSessionTTL: services.Duration{Duration: time.Hour},
|
||||
},
|
||||
Allow: services.RoleConditions{
|
||||
Logins: []string{"root", "bob"},
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
Namespaces: []string{"default", "system"},
|
||||
Rules: map[string][]string{
|
||||
services.KindRole: services.RO(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err = s.Access.UpsertRole(&role, backend.Forever)
|
||||
|
@ -399,7 +405,7 @@ func (s *ServicesTestSuite) RolesCRUD(c *C) {
|
|||
c.Assert(err, IsNil)
|
||||
c.Assert(rout, DeepEquals, &role)
|
||||
|
||||
role.Spec.Logins = []string{"bob"}
|
||||
role.Spec.Allow.Logins = []string{"bob"}
|
||||
err = s.Access.UpsertRole(&role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
rout, err = s.Access.GetRole(role.Metadata.Name)
|
||||
|
|
|
@ -189,7 +189,7 @@ func (r *ReverseTunnelV1) V2() *ReverseTunnelV2 {
|
|||
// GetReverseTunnelSchema returns role schema with optionally injected
|
||||
// schema for extensions
|
||||
func GetReverseTunnelSchema() string {
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ReverseTunnelSpecV2Schema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ReverseTunnelSpecV2Schema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
// UnmarshalReverseTunnel unmarshals reverse tunnel from JSON or YAML,
|
||||
|
|
|
@ -139,7 +139,7 @@ func GetUniversalSecondFactorSchema(extensionSchema string) string {
|
|||
} else {
|
||||
authPreferenceSchema = fmt.Sprintf(UniversalSecondFactorSpecSchemaTemplate, ","+extensionSchema)
|
||||
}
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, authPreferenceSchema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, authPreferenceSchema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
// UniversalSecondFactorMarshaler implements marshal/unmarshal of UniversalSecondFactor implementations
|
||||
|
|
|
@ -491,7 +491,7 @@ func GetUserSchema(extensionSchema string) string {
|
|||
} else {
|
||||
userSchema = fmt.Sprintf(UserSpecV2SchemaTemplate, ExternalIdentitySchema, ExternalIdentitySchema, LoginStatusSchema, CreatedBySchema, ", "+extensionSchema)
|
||||
}
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, userSchema)
|
||||
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, userSchema, DefaultDefinitions)
|
||||
}
|
||||
|
||||
type TeleportUserMarshaler struct{}
|
||||
|
|
|
@ -225,7 +225,9 @@ func (s *SrvSuite) TestAgentForward(c *C) {
|
|||
roleName := services.RoleNameForUser(s.user)
|
||||
role, err := s.a.GetRole(roleName)
|
||||
c.Assert(err, IsNil)
|
||||
role.SetForwardAgent(true)
|
||||
roleOptions := role.GetOptions()
|
||||
roleOptions.Set(services.ForwardAgent, true)
|
||||
role.SetOptions(roleOptions)
|
||||
err = s.a.UpsertRole(role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
|
@ -917,8 +919,10 @@ func newUpack(username string, allowedLogins []string, a *auth.AuthServer) (*upa
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
role := services.RoleForUser(user)
|
||||
role.SetResource(services.Wildcard, services.RW())
|
||||
role.SetLogins(allowedLogins)
|
||||
resources := role.GetSystemResources(services.Allow)
|
||||
resources[services.Wildcard] = services.RW()
|
||||
role.SetSystemResources(services.Allow, resources)
|
||||
role.SetLogins(services.Allow, allowedLogins)
|
||||
err = a.UpsertRole(role, backend.Forever)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
76
lib/utils/copy.go
Normal file
76
lib/utils/copy.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
// CopyStrings makes a deep copy of the passed in string slice and returns
|
||||
// the copy.
|
||||
func CopyStrings(in []string) []string {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make([]string, len(in))
|
||||
copy(out, in)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// CopyStringMapSlices makes a deep copy of the passed in map[string][]string
|
||||
// and returns the copy.
|
||||
func CopyStringMapSlices(a map[string][]string) map[string][]string {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make(map[string][]string)
|
||||
for key, values := range a {
|
||||
vout := make([]string, len(values))
|
||||
copy(vout, values)
|
||||
out[key] = vout
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// CopyStringMap makes a deep copy of a map[string]string and returns the copy.
|
||||
func CopyStringMap(a map[string]string) map[string]string {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make(map[string]string)
|
||||
for key, value := range a {
|
||||
out[key] = value
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// CopyStringMapInterface makes a deep copy of the passed in map[string]interface{}
|
||||
// and returns the copy.
|
||||
func CopyStringMapInterface(a map[string]interface{}) map[string]interface{} {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make(map[string]interface{})
|
||||
for key, value := range a {
|
||||
out[key] = value
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
|
@ -42,6 +42,19 @@ func StringMapsEqual(a, b map[string]string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// InterfaceMapsEqual returns true if two interface maps are equal.
|
||||
func InterfaceMapsEqual(a, b map[string]interface{}) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for key := range a {
|
||||
if a[key] != b[key] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// StringMapSlicesEqual returns true if two maps of string slices are equal
|
||||
func StringMapSlicesEqual(a, b map[string][]string) bool {
|
||||
if len(a) != len(b) {
|
||||
|
|
|
@ -33,15 +33,6 @@ import (
|
|||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func CopyStrings(in []string) []string {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := make([]string, len(in))
|
||||
copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
type HostKeyCallback func(hostID string, remote net.Addr, key ssh.PublicKey) error
|
||||
|
||||
func ReadPath(path string) ([]byte, error) {
|
||||
|
|
|
@ -340,7 +340,10 @@ func (m *Handler) getUserACL(w http.ResponseWriter, r *http.Request, _ httproute
|
|||
accessSet := []*ui.RoleAccess{}
|
||||
for _, item := range allTeleRoles {
|
||||
if roleNamesMap[item.GetName()] {
|
||||
uiRole := ui.NewRole(item)
|
||||
uiRole, err := ui.NewRole(item)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
accessSet = append(accessSet, &uiRole.Access)
|
||||
}
|
||||
}
|
||||
|
@ -701,7 +704,7 @@ func NewSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) {
|
|||
}
|
||||
roles = append(roles, role)
|
||||
}
|
||||
allowedLogins, err := roles.CheckLogins(0)
|
||||
allowedLogins, err := roles.CheckLoginDuration(0)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -194,8 +194,10 @@ func (s *WebSuite) SetUpTest(c *C) {
|
|||
teleUser, err := services.NewUser(s.user)
|
||||
c.Assert(err, IsNil)
|
||||
role := services.RoleForUser(teleUser)
|
||||
role.SetLogins([]string{s.user})
|
||||
role.SetResource(services.Wildcard, services.RW())
|
||||
role.SetLogins(services.Allow, []string{s.user})
|
||||
resources := role.GetSystemResources(services.Allow)
|
||||
resources[services.Wildcard] = services.RW()
|
||||
role.SetSystemResources(services.Allow, resources)
|
||||
err = s.authServer.UpsertRole(role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
|
@ -435,16 +437,20 @@ func (s *WebSuite) TestSAMLSuccess(c *C) {
|
|||
c.Assert(err, IsNil)
|
||||
err = connector.CheckAndSetDefaults()
|
||||
|
||||
role, err := services.NewRole(connector.GetAttributesToRoles()[0].Roles[0], services.RoleSpecV2{
|
||||
MaxSessionTTL: services.NewDuration(defaults.MaxCertDuration),
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Resources: map[string][]string{
|
||||
services.Wildcard: services.RW(),
|
||||
role, err := services.NewRole(connector.GetAttributesToRoles()[0].Roles[0], services.RoleSpecV3{
|
||||
Options: services.RoleOptions{
|
||||
services.MaxSessionTTL: services.NewDuration(defaults.MaxCertDuration),
|
||||
},
|
||||
Allow: services.RoleConditions{
|
||||
NodeLabels: map[string]string{services.Wildcard: services.Wildcard},
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
Rules: map[string][]string{
|
||||
services.Wildcard: services.RW(),
|
||||
},
|
||||
},
|
||||
})
|
||||
c.Assert(err, IsNil)
|
||||
role.SetLogins([]string{s.user})
|
||||
role.SetLogins(services.Allow, []string{s.user})
|
||||
err = s.roleAuth.UpsertRole(role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
|
@ -551,7 +557,7 @@ func (s *WebSuite) authPack(c *C) *authPack {
|
|||
teleUser, err := services.NewUser(user)
|
||||
c.Assert(err, IsNil)
|
||||
role := services.RoleForUser(teleUser)
|
||||
role.SetLogins([]string{s.user})
|
||||
role.SetLogins(services.Allow, []string{s.user})
|
||||
err = s.roleAuth.UpsertRole(role, backend.Forever)
|
||||
c.Assert(err, IsNil)
|
||||
teleUser.AddRole(role.GetName())
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package ui
|
||||
|
||||
import teleservices "github.com/gravitational/teleport/lib/services"
|
||||
import (
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// Role describes user role consumed by web ui
|
||||
type Role struct {
|
||||
|
@ -13,18 +17,22 @@ type Role struct {
|
|||
}
|
||||
|
||||
// NewRole creates a new instance of UI Role
|
||||
func NewRole(sRole teleservices.Role) *Role {
|
||||
func NewRole(sRole services.Role) (*Role, error) {
|
||||
uiRole := Role{
|
||||
Name: sRole.GetName(),
|
||||
}
|
||||
|
||||
uiRole.Access.init(sRole)
|
||||
return &uiRole
|
||||
err := uiRole.Access.init(sRole)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return &uiRole, nil
|
||||
}
|
||||
|
||||
// ToTeleRole converts UI Role to Storage Role
|
||||
func (r *Role) ToTeleRole() (teleservices.Role, error) {
|
||||
teleRole, err := teleservices.NewRole(r.Name, teleservices.RoleSpecV2{})
|
||||
func (r *Role) ToTeleRole() (services.Role, error) {
|
||||
teleRole, err := services.NewRole(r.Name, services.RoleSpecV3{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ package ui
|
|||
import (
|
||||
"time"
|
||||
|
||||
teleservices "github.com/gravitational/teleport/lib/services"
|
||||
teleutils "github.com/gravitational/teleport/lib/utils"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -15,13 +17,13 @@ const (
|
|||
)
|
||||
|
||||
var adminResources = []string{
|
||||
teleservices.KindRole,
|
||||
teleservices.KindUser,
|
||||
teleservices.KindOIDC,
|
||||
teleservices.KindCertAuthority,
|
||||
teleservices.KindReverseTunnel,
|
||||
teleservices.KindTrustedCluster,
|
||||
teleservices.KindNode,
|
||||
services.KindRole,
|
||||
services.KindUser,
|
||||
services.KindOIDC,
|
||||
services.KindCertAuthority,
|
||||
services.KindReverseTunnel,
|
||||
services.KindTrustedCluster,
|
||||
services.KindNode,
|
||||
}
|
||||
|
||||
// AdminAccess describes admin access
|
||||
|
@ -52,7 +54,7 @@ type RoleAccess struct {
|
|||
func MergeAccessSet(accessList []*RoleAccess) *RoleAccess {
|
||||
uiAccess := RoleAccess{}
|
||||
for _, item := range accessList {
|
||||
uiAccess.SSH.Logins = teleutils.Deduplicate(append(uiAccess.SSH.Logins, item.SSH.Logins...))
|
||||
uiAccess.SSH.Logins = utils.Deduplicate(append(uiAccess.SSH.Logins, item.SSH.Logins...))
|
||||
uiAccess.Admin.Enabled = item.Admin.Enabled || uiAccess.Admin.Enabled
|
||||
}
|
||||
|
||||
|
@ -60,84 +62,95 @@ func MergeAccessSet(accessList []*RoleAccess) *RoleAccess {
|
|||
}
|
||||
|
||||
// Apply applies this role access to Teleport Role
|
||||
func (a *RoleAccess) Apply(teleRole teleservices.Role) {
|
||||
func (a *RoleAccess) Apply(teleRole services.Role) {
|
||||
a.applyAdmin(teleRole)
|
||||
a.applySSH(teleRole)
|
||||
}
|
||||
|
||||
func (a *RoleAccess) init(teleRole teleservices.Role) {
|
||||
func (a *RoleAccess) init(teleRole services.Role) error {
|
||||
a.initAdmin(teleRole)
|
||||
a.initSSH(teleRole)
|
||||
|
||||
err := a.initSSH(teleRole)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *RoleAccess) initSSH(teleRole teleservices.Role) {
|
||||
a.SSH.MaxSessionTTL = teleRole.GetMaxSessionTTL().Duration
|
||||
a.SSH.NodeLabels = teleRole.GetNodeLabels()
|
||||
func (a *RoleAccess) initSSH(teleRole services.Role) error {
|
||||
maxSessionTTL, err := teleRole.GetOptions().GetDuration(services.MaxSessionTTL)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
a.SSH.MaxSessionTTL = maxSessionTTL.Duration
|
||||
|
||||
a.SSH.NodeLabels = teleRole.GetNodeLabels(services.Allow)
|
||||
|
||||
// FIXME: this is a workaround for #1623
|
||||
filteredLogins := []string{}
|
||||
for _, login := range teleRole.GetLogins() {
|
||||
for _, login := range teleRole.GetLogins(services.Allow) {
|
||||
if login != roleDefaultAllowedLogin {
|
||||
filteredLogins = append(filteredLogins, login)
|
||||
}
|
||||
}
|
||||
|
||||
a.SSH.Logins = filteredLogins
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *RoleAccess) initAdmin(teleRole teleservices.Role) {
|
||||
hasAllNamespaces := teleservices.MatchNamespace(
|
||||
teleRole.GetNamespaces(),
|
||||
teleservices.Wildcard)
|
||||
func (a *RoleAccess) initAdmin(teleRole services.Role) {
|
||||
hasAllNamespaces := services.MatchNamespace(
|
||||
teleRole.GetNamespaces(services.Allow),
|
||||
services.Wildcard)
|
||||
|
||||
resources := teleRole.GetResources()
|
||||
resources := teleRole.GetSystemResources(services.Allow)
|
||||
a.Admin.Enabled = hasFullAccess(resources, adminResources) && hasAllNamespaces
|
||||
}
|
||||
|
||||
func (a *RoleAccess) applyAdmin(teleRole teleservices.Role) {
|
||||
func (a *RoleAccess) applyAdmin(role services.Role) {
|
||||
if a.Admin.Enabled {
|
||||
allowAllNamespaces(teleRole)
|
||||
applyResourceAccess(teleRole, adminResources, teleservices.RW())
|
||||
allowAllNamespaces(role)
|
||||
applyResourceAccess(role, adminResources, services.RW())
|
||||
} else {
|
||||
teleRole.RemoveResource(teleservices.Wildcard)
|
||||
applyResourceAccess(teleRole, adminResources, teleservices.RO())
|
||||
resources := role.GetSystemResources(services.Allow)
|
||||
delete(resources, services.Wildcard)
|
||||
role.SetSystemResources(services.Allow, resources)
|
||||
applyResourceAccess(role, adminResources, services.RO())
|
||||
}
|
||||
}
|
||||
|
||||
func (a *RoleAccess) applySSH(teleRole teleservices.Role) {
|
||||
func (a *RoleAccess) applySSH(teleRole services.Role) {
|
||||
// FIXME: this is a workaround for #1623
|
||||
if len(a.SSH.Logins) == 0 {
|
||||
a.SSH.Logins = append(a.SSH.Logins, roleDefaultAllowedLogin)
|
||||
}
|
||||
|
||||
teleRole.SetMaxSessionTTL(a.SSH.MaxSessionTTL)
|
||||
teleRole.SetLogins(a.SSH.Logins)
|
||||
teleRole.SetNodeLabels(a.SSH.NodeLabels)
|
||||
roleOptions := teleRole.GetOptions()
|
||||
roleOptions[services.MaxSessionTTL] = services.NewDuration(a.SSH.MaxSessionTTL)
|
||||
teleRole.SetOptions(roleOptions)
|
||||
|
||||
teleRole.SetLogins(services.Allow, a.SSH.Logins)
|
||||
teleRole.SetNodeLabels(services.Allow, a.SSH.NodeLabels)
|
||||
}
|
||||
|
||||
func all() []string {
|
||||
return []string{teleservices.Wildcard}
|
||||
return []string{services.Wildcard}
|
||||
}
|
||||
|
||||
func allowAllNamespaces(teleRole teleservices.Role) {
|
||||
newNamespaces := teleutils.Deduplicate(append(teleRole.GetNamespaces(), all()...))
|
||||
teleRole.SetNamespaces(newNamespaces)
|
||||
func allowAllNamespaces(teleRole services.Role) {
|
||||
newNamespaces := utils.Deduplicate(append(teleRole.GetNamespaces(services.Allow), all()...))
|
||||
teleRole.SetNamespaces(services.Allow, newNamespaces)
|
||||
}
|
||||
|
||||
func none() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasFullAccess(resources map[string][]string, kinds []string) bool {
|
||||
for _, kind := range kinds {
|
||||
hasRead := teleservices.MatchResourceAction(
|
||||
resources,
|
||||
kind,
|
||||
teleservices.ActionRead)
|
||||
|
||||
hasWrite := teleservices.MatchResourceAction(
|
||||
resources,
|
||||
kind,
|
||||
teleservices.ActionWrite)
|
||||
func hasFullAccess(rules map[string][]string, resources []string) bool {
|
||||
for _, resource := range resources {
|
||||
hasRead := services.MatchRule(rules, resource, services.ActionRead)
|
||||
hasWrite := services.MatchRule(rules, resource, services.ActionWrite)
|
||||
|
||||
if !(hasRead && hasWrite) {
|
||||
return false
|
||||
|
@ -147,8 +160,10 @@ func hasFullAccess(resources map[string][]string, kinds []string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func applyResourceAccess(teleRole teleservices.Role, kinds []string, actions []string) {
|
||||
for _, kind := range kinds {
|
||||
teleRole.SetResource(kind, actions)
|
||||
func applyResourceAccess(role services.Role, resources []string, verbs []string) {
|
||||
rs := role.GetSystemResources(services.Allow)
|
||||
for _, resource := range resources {
|
||||
rs[resource] = verbs
|
||||
}
|
||||
role.SetSystemResources(services.Allow, rs)
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@ func (r *roleCollection) writeText(w io.Writer) error {
|
|||
for _, r := range r.roles {
|
||||
fmt.Fprintf(t, "%v\t%v\t%v\t%v\t%v\n",
|
||||
r.GetMetadata().Name,
|
||||
strings.Join(r.GetLogins(), ","),
|
||||
strings.Join(r.GetNamespaces(), ","),
|
||||
printNodeLabels(r.GetNodeLabels()),
|
||||
printActions(r.GetResources()))
|
||||
strings.Join(r.GetLogins(services.Allow), ","),
|
||||
strings.Join(r.GetNamespaces(services.Allow), ","),
|
||||
printNodeLabels(r.GetNodeLabels(services.Allow)),
|
||||
printActions(r.GetRules(services.Allow)))
|
||||
}
|
||||
_, err := io.WriteString(w, t.String())
|
||||
return trace.Wrap(err)
|
||||
|
|
|
@ -593,7 +593,7 @@ func hostCAFormat(ca services.CertAuthority, keyBytes []byte, client *auth.TunCl
|
|||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
allowedLogins, _ := roles.CheckLogins(defaults.MinCertDuration + time.Second)
|
||||
allowedLogins, _ := roles.CheckLoginDuration(defaults.MinCertDuration + time.Second)
|
||||
if len(allowedLogins) > 0 {
|
||||
comment["logins"] = allowedLogins
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue