From cedacb92aaf4b25f898c95735e7add9adefb4095 Mon Sep 17 00:00:00 2001 From: Sasha Klizhentas Date: Fri, 16 Dec 2016 11:25:17 -0800 Subject: [PATCH] migrate users, add role per user --- lib/auth/init.go | 17 +++++++++++++++++ lib/auth/new_web_user.go | 30 ++++++++++++++++++++++++++---- lib/services/role.go | 22 ++++++++++++++++++++++ lib/web/web.go | 30 +++++++++++++++++++++++------- 4 files changed, 88 insertions(+), 11 deletions(-) diff --git a/lib/auth/init.go b/lib/auth/init.go index 0509fa84998..78e642dd6df 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -255,6 +255,23 @@ func Init(cfg InitConfig, seedConfig bool) (*AuthServer, *Identity, error) { } } + // migrate old users to new users + users, err := asrv.GetUsers() + for _, user := range users { + _, err := asrv.GetRole(services.RoleNameForUser(user.GetName())) + if err == nil { + continue + } + if !trace.IsNotFound(err) { + return nil, nil, trace.Wrap(err) + } + log.Infof("migrating legacy user %v", user.GetName()) + err = asrv.UpsertRole(services.RoleForUser(user)) + if err != nil { + return nil, nil, trace.Wrap(err) + } + } + identity, err := initKeys(asrv, cfg.DataDir, IdentityID{HostUUID: cfg.HostUUID, Role: teleport.RoleAdmin}) if err != nil { diff --git a/lib/auth/new_web_user.go b/lib/auth/new_web_user.go index e54516e5d6b..0e230454993 100644 --- a/lib/auth/new_web_user.go +++ b/lib/auth/new_web_user.go @@ -140,7 +140,7 @@ func (s *AuthServer) CreateSignupU2FRegisterRequest(token string) (u2fRegisterRe return nil, trace.Wrap(err) } - lock := "signuptoken"+token + lock := "signuptoken" + token err = s.AcquireLock(lock, time.Hour) if err != nil { @@ -216,6 +216,11 @@ func (s *AuthServer) CreateUserWithToken(token, password, hotpToken string) (*Se } // apply user allowed logins + if err := s.UpsertRole(services.RoleForUser(&tokenData.User)); err != nil { + return nil, trace.Wrap(err) + } + // Allowed logins are not going to be used anymore + tokenData.User.AllowedLogins = nil if err = s.UpsertUser(&tokenData.User); err != nil { return nil, trace.Wrap(err) } @@ -251,7 +256,7 @@ func (s *AuthServer) CreateUserWithU2FToken(token string, password string, respo return nil, trace.Wrap(err) } - lock := "signuptoken"+token + lock := "signuptoken" + token err = s.AcquireLock(lock, time.Hour) if err != nil { @@ -294,8 +299,11 @@ func (s *AuthServer) CreateUserWithU2FToken(token string, password string, respo if err != nil { return nil, trace.Wrap(err) } - - // apply user allowed logins + if err := s.UpsertRole(services.RoleForUser(&tokenData.User)); err != nil { + return nil, trace.Wrap(err) + } + // Allowed logins are not going to be used anymore + tokenData.User.AllowedLogins = nil if err = s.UpsertUser(&tokenData.User); err != nil { return nil, trace.Wrap(err) } @@ -319,3 +327,17 @@ func (s *AuthServer) CreateUserWithU2FToken(token string, password string, respo sess.WS.Priv = nil return sess, nil } + +func (a *AuthServer) DeleteUser(user string) error { + role, err := a.Access.GetRole(services.RoleNameForUser(user)) + if err != nil { + if !trace.IsNotFound(err) { + return trace.Wrap(err) + } + } else { + if err := a.Access.DeleteRole(role.GetMetadata().Name); err != nil { + return trace.Wrap(err) + } + } + return a.Identity.DeleteUser(user) +} diff --git a/lib/services/role.go b/lib/services/role.go index 1560d060246..48e4be4ee15 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -29,6 +29,28 @@ import ( "github.com/gravitational/trace" ) +// RoleForUser returns role name associated with user +func RoleNameForUser(name string) string { + return "user:" + name +} + +// RoleForUser creates role using AllowedLogins parameter +func RoleForUser(u User) Role { + return &RoleResource{ + Kind: KindRole, + Version: V1, + Metadata: Metadata{ + Name: RoleNameForUser(u.GetName()), + Namespace: defaults.Namespace, + }, + Spec: RoleSpec{ + MaxSessionTTL: NewDuration(defaults.MaxCertDuration), + NodeLabels: map[string]string{Wildcard: Wildcard}, + Namespaces: []string{defaults.Namespace}, + }, + } +} + // Access service manages roles and permissions type Access interface { // GetRoles returns a list of roles diff --git a/lib/web/web.go b/lib/web/web.go index 1244543a3f3..1e072db274d 100644 --- a/lib/web/web.go +++ b/lib/web/web.go @@ -94,8 +94,17 @@ type Config struct { // Version is a current webapi version const APIVersion = "v1" +type RewritingHandler struct { + http.Handler + handler *Handler +} + +func (r *RewritingHandler) Close() error { + return r.handler.Close() +} + // NewHandler returns a new instance of web proxy handler -func NewHandler(cfg Config, opts ...HandlerOption) (*Handler, error) { +func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { const apiPrefix = "/" + APIVersion lauth, err := newSessionCache([]utils.NetAddr{cfg.AuthServers}) if err != nil { @@ -242,7 +251,15 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*Handler, error) { } }) h.NotFound = routingHandler - return h, nil + return &RewritingHandler{ + Handler: httplib.RewritePaths(h, + httplib.Rewrite("/webapi/sites/([^/]+)/sessions/(.*)", "/webapi/sites/$1/namespaces/default/sessions/$2/$3"), + httplib.Rewrite("/webapi/sites/([^/]+)/sessions", "/webapi/sites/$1/namespaces/default/sessions"), + httplib.Rewrite("/webapi/sites/([^/]+)/nodes", "/webapi/sites/$1/namespaces/default/nodes"), + httplib.Rewrite("/webapi/sites/([^/]+)/connect", "/webapi/sites/$1/namespaces/default/connect"), + ), + handler: h, + }, nil } // Close closes associated session cache operations @@ -258,7 +275,7 @@ type oidcConnector struct { type webSettings struct { Auth struct { OIDCConnectors []oidcConnector `json:"oidc_connectors"` - U2FAppID string `json:"u2f_appid"` + U2FAppID string `json:"u2f_appid"` } `json:"auth"` } @@ -594,7 +611,6 @@ func (m *Handler) renderUserInvite(w http.ResponseWriter, r *http.Request, p htt }, nil } - // u2fRegisterRequest is called to get a U2F challenge for registering a U2F key // // GET /webapi/u2f/signuptokens/:token @@ -645,7 +661,7 @@ func (m *Handler) u2fSignRequest(w http.ResponseWriter, r *http.Request, p httpr // A request from the client to send the signature from the U2F key type u2fSignResponseReq struct { - User string `json:"user"` + User string `json:"user"` U2FSignResponse u2f.SignResponse `json:"u2f_sign_response"` } @@ -717,8 +733,8 @@ func (m *Handler) createNewUser(w http.ResponseWriter, r *http.Request, p httpro // A request to create a new user which uses U2F as the second factor type createNewU2FUserReq struct { - InviteToken string `json:"invite_token"` - Pass string `json:"pass"` + InviteToken string `json:"invite_token"` + Pass string `json:"pass"` U2FRegisterResponse u2f.RegisterResponse `json:"u2f_register_response"` }