diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 097f42bf225..19e543c587c 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -360,7 +360,7 @@ func (s *APIServer) upsertUser(w http.ResponseWriter, r *http.Request, p httprou if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) } - user, err := services.GetUserUnmarshaler()(req.User) + user, err := services.GetUserMarshaler().UnmarshalUser(req.User) if err != nil { return nil, trace.Wrap(err) } @@ -668,7 +668,7 @@ func (s *APIServer) createSignupToken(w http.ResponseWriter, r *http.Request, p if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) } - user, err := services.GetUserUnmarshaler()(req.User) + user, err := services.GetUserMarshaler().UnmarshalUser(req.User) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/clt.go b/lib/auth/clt.go index e879b9f39b3..a5ed454392c 100644 --- a/lib/auth/clt.go +++ b/lib/auth/clt.go @@ -511,7 +511,7 @@ func (c *Client) GetUser(name string) (services.User, error) { if err != nil { return nil, trace.Wrap(err) } - user, err := services.GetUserUnmarshaler()(out.Bytes()) + user, err := services.GetUserMarshaler().UnmarshalUser(out.Bytes()) if err != nil { return nil, trace.Wrap(err) } @@ -530,7 +530,7 @@ func (c *Client) GetUsers() ([]services.User, error) { } users := make([]services.User, len(items)) for i, userBytes := range items { - user, err := services.GetUserUnmarshaler()(userBytes) + user, err := services.GetUserMarshaler().UnmarshalUser(userBytes) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/identity.go b/lib/services/identity.go index 990d9592a91..27d7419218e 100644 --- a/lib/services/identity.go +++ b/lib/services/identity.go @@ -404,26 +404,33 @@ func (u Users) Swap(i, j int) { } var mtx sync.Mutex -var unmarshaler UserUnmarshaler +var userMarshaler UserMarshaler = &TeleportUserMarshaler{} -func SetUserUnmarshaler(u UserUnmarshaler) { +func SetUserMarshaler(u UserMarshaler) { mtx.Lock() defer mtx.Unlock() - unmarshaler = u + userMarshaler = u } -func GetUserUnmarshaler() UserUnmarshaler { +func GetUserMarshaler() UserMarshaler { mtx.Lock() defer mtx.Unlock() - if unmarshaler == nil { - return TeleportUserUnmarshaler - } - return unmarshaler + return userMarshaler } -type UserUnmarshaler func(bytes []byte) (User, error) +// UserMarshaler implements marshal/unmarshal of User implementations +// mostly adds support for extended versions +type UserMarshaler interface { + // UnmarshalUser from binary representation + UnmarshalUser(bytes []byte) (User, error) + // MarshalUser to binary representation + MarshalUser(u User) ([]byte, error) +} -func TeleportUserUnmarshaler(bytes []byte) (User, error) { +type TeleportUserMarshaler struct{} + +// UnmarshalUser unmarshals user from JSON +func (*TeleportUserMarshaler) UnmarshalUser(bytes []byte) (User, error) { var u *TeleportUser err := json.Unmarshal(bytes, &u) if err != nil { @@ -431,3 +438,8 @@ func TeleportUserUnmarshaler(bytes []byte) (User, error) { } return u, nil } + +// MarshalUser marshalls user into JSON +func (*TeleportUserMarshaler) MarshalUser(u User) ([]byte, error) { + return json.Marshal(u) +} diff --git a/lib/services/role.go b/lib/services/role.go index 953b0fcf146..c361f302449 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -49,6 +49,22 @@ const ( V1 = "v1" ) +// Role contains a set of permissions or settings +type Role interface { + // GetMetadata returns role metadata + GetMetadata() Metadata + // GetMaxSessionTTL is a maximum SSH or Web session TTL + GetMaxSessionTTL() Duration + // GetLogins returns a list of linux logins allowed for this role + GetLogins() []string + // GetNodeLabels returns a list of matchign nodes this role has access to + GetNodeLabels() map[string]string + // GetNamespaces returns a list of namespaces this role has access to + GetNamespaces() []string + // GetResources returns access to resources + GetResources() map[string][]string +} + // Metadata is resource metadata type Metadata struct { // Name is an object name @@ -73,6 +89,36 @@ type RoleResource struct { Spec RoleSpec `json:"spec"` } +// GetMetadata returns role metadata +func (r *RoleResource) GetMetadata() Metadata { + return r.Metadata +} + +// GetMaxSessionTTL is a maximum SSH or Web session TTL +func (r *RoleResource) GetMaxSessionTTL() Duration { + return r.Spec.MaxSessionTTL +} + +// GetLogins returns a list of linux logins allowed for this role +func (r *RoleResource) GetLogins() []string { + return r.Spec.Logins +} + +// GetNodeLabels returns a list of matchign nodes this role has access to +func (r *RoleResource) GetNodeLabels() map[string]string { + return r.Spec.NodeLabels +} + +// GetNamespaces returns a list of namespaces this role has access to +func (r *RoleResource) GetNamespaces() []string { + return r.Spec.Namespaces +} + +// GetResources returns access to resources +func (r *RoleResource) GetResources() map[string][]string { + return r.Spec.Resources +} + // RoleSpec is role specification type RoleSpec struct { // MaxSessionTTL is a maximum SSH or Web session TTL @@ -115,19 +161,6 @@ func (d *Duration) UnmarshalJSON(data []byte) error { return nil } -// UnmarshalRole unmarshals role from JSON or YAML, -// sets defaults and checks the schema -func UnmarshalRole(data []byte) (*RoleResource, error) { - if len(data) == 0 { - return nil, trace.BadParameter("empty input") - } - var role RoleResource - if err := utils.UnmarshalWithSchema(RoleSchema, &role, data); err != nil { - return nil, trace.BadParameter(err.Error()) - } - return &role, nil -} - const MetadataSchema = `{ "type": "object", "additionalProperties": false, @@ -209,3 +242,51 @@ const NodeSelectorSchema = `{ } } }` + +// UnmarshalRoleResource unmarshals role from JSON or YAML, +// sets defaults and checks the schema +func UnmarshalRoleResource(data []byte) (*RoleResource, error) { + if len(data) == 0 { + return nil, trace.BadParameter("empty input") + } + var role RoleResource + if err := utils.UnmarshalWithSchema(RoleSchema, &role, data); err != nil { + return nil, trace.BadParameter(err.Error()) + } + return &role, nil +} + +var roleMarshaler RoleMarshaler = &TeleportRoleMarshaler{} + +func SetRoleMarshaler(u RoleMarshaler) { + mtx.Lock() + defer mtx.Unlock() + roleMarshaler = u +} + +func GetRoleMarshaler() RoleMarshaler { + mtx.Lock() + defer mtx.Unlock() + return roleMarshaler +} + +// RoleMarshaler implements marshal/unmarshal of Role implementations +// mostly adds support for extended versions +type RoleMarshaler interface { + // UnmarshalRole from binary representation + UnmarshalRole(bytes []byte) (Role, error) + // MarshalRole to binary representation + MarshalRole(u Role) ([]byte, error) +} + +type TeleportRoleMarshaler struct{} + +// UnmarshalRole unmarshals role from JSON +func (*TeleportRoleMarshaler) UnmarshalRole(bytes []byte) (Role, error) { + return UnmarshalRoleResource(bytes) +} + +// MarshalRole marshalls role into JSON +func (*TeleportRoleMarshaler) MarshalRole(u Role) ([]byte, error) { + return json.Marshal(u) +} diff --git a/lib/services/role_test.go b/lib/services/role_test.go index 2c598e93e5e..814e4af4ca1 100644 --- a/lib/services/role_test.go +++ b/lib/services/role_test.go @@ -18,7 +18,6 @@ package services import ( "encoding/json" - "fmt" "testing" "time" @@ -121,7 +120,7 @@ spec: } for i, tc := range testCases { comment := Commentf("test case %v", i) - role, err := UnmarshalRole([]byte(tc.in)) + role, err := UnmarshalRoleResource([]byte(tc.in)) if tc.error != nil { c.Assert(err, NotNil, comment) } else { @@ -131,9 +130,7 @@ spec: out, err := json.Marshal(*role) c.Assert(err, IsNil, comment) - fmt.Printf("out: %v\n", string(out)) - - role2, err := UnmarshalRole(out) + role2, err := UnmarshalRoleResource(out) c.Assert(err, IsNil, comment) c.Assert(*role2, DeepEquals, tc.role, comment) } diff --git a/lib/web/web.go b/lib/web/web.go index 5fe2dfc95c2..d8f1f49ab17 100644 --- a/lib/web/web.go +++ b/lib/web/web.go @@ -444,7 +444,7 @@ type createSessionResponseRaw struct { } func (r createSessionResponseRaw) response() (*CreateSessionResponse, error) { - user, err := services.GetUserUnmarshaler()(r.User) + user, err := services.GetUserMarshaler().UnmarshalUser(r.User) if err != nil { return nil, trace.Wrap(err) }