diff --git a/Makefile b/Makefile index cd97f434d513f..fdb7e64e0a950 100644 --- a/Makefile +++ b/Makefile @@ -291,6 +291,8 @@ grpc: buildbox buildbox-grpc: # standard GRPC output echo $$PROTO_INCLUDE + find lib/ -iname *.proto | xargs clang-format -i -style='{ColumnLimit: 100, IndentWidth: 4, Language: Proto}' + cd lib/events && protoc -I=.:$$PROTO_INCLUDE \ --gofast_out=plugins=grpc:.\ *.proto diff --git a/build.assets/grpc/Dockerfile b/build.assets/grpc/Dockerfile index be1539799fc26..5f55baf4391d1 100644 --- a/build.assets/grpc/Dockerfile +++ b/build.assets/grpc/Dockerfile @@ -7,7 +7,7 @@ ARG PLATFORM ENV TARBALL protoc-${PROTOC_VER}-${PLATFORM}.zip ENV GOGOPROTO_ROOT ${GOPATH}/src/github.com/gogo/protobuf -RUN apt-get update && apt-get install unzip +RUN apt-get update && apt-get install unzip clang-format -y RUN curl -L -o /tmp/${TARBALL} https://github.com/google/protobuf/releases/download/v${PROTOC_VER}/${TARBALL} RUN cd /tmp && unzip /tmp/protoc-${PROTOC_VER}-linux-x86_64.zip -d /usr/local && rm /tmp/${TARBALL} diff --git a/integration/integration_test.go b/integration/integration_test.go index 67d05e702f322..61fb30cb31b48 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -44,7 +44,6 @@ import ( "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/testauthority" - "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/bpf" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/defaults" @@ -3712,70 +3711,6 @@ func (s *IntSuite) TestList(c *check.C) { } } -// TestMultipleSignup makes sure that multiple users can create Teleport accounts. -func (s *IntSuite) TestMultipleSignup(c *check.C) { - tr := utils.NewTracer(utils.ThisFunction()).Start() - defer tr.Stop() - - type createNewUserReq struct { - InviteToken string `json:"invite_token"` - Pass string `json:"pass"` - } - - // Create and start a Teleport cluster. - makeConfig := func() (*check.C, []string, []*InstanceSecrets, *service.Config) { - clusterConfig, err := services.NewClusterConfig(services.ClusterConfigSpecV3{ - SessionRecording: services.RecordAtNode, - LocalAuth: services.NewBool(true), - }) - c.Assert(err, check.IsNil) - - tconf := service.MakeDefaultConfig() - tconf.Auth.Preference.SetSecondFactor("off") - tconf.Auth.Enabled = true - tconf.Auth.ClusterConfig = clusterConfig - tconf.Proxy.Enabled = true - tconf.Proxy.DisableWebService = false - tconf.Proxy.DisableWebInterface = true - tconf.SSH.Enabled = true - return c, nil, nil, tconf - } - main := s.newTeleportWithConfig(makeConfig()) - defer main.Stop(true) - - mainAuth := main.Process.GetAuthServer() - - // Create a few users to make sure the proxy uses the correct identity - // when connecting to the auth server. - for i := 0; i < 5; i++ { - // Create a random username. - username, err := utils.CryptoRandomHex(16) - c.Assert(err, check.IsNil) - - // Create signup token, this is like doing "tctl users add foo foo". - token, err := mainAuth.CreateSignupToken(services.UserV1{ - Name: username, - AllowedLogins: []string{username}, - }, backend.Forever) - c.Assert(err, check.IsNil) - - // Create client that will simulate web browser. - clt, err := createWebClient(main) - c.Assert(err, check.IsNil) - - // Render the signup page. - _, err = clt.Get(context.Background(), clt.Endpoint("webapi", "users", "invites", token), url.Values{}) - c.Assert(err, check.IsNil) - - // Make sure signup is successful. - _, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "users"), createNewUserReq{ - InviteToken: token, - Pass: "fake-password-123", - }) - c.Assert(err, check.IsNil) - } -} - // TestDataTransfer makes sure that a "session.data" event is emitted at the // end of a session that matches the amount of data that was transferred. func (s *IntSuite) TestDataTransfer(c *check.C) { diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 3a6e5e9b613d6..9cb5ef79ed115 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -42,7 +42,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" "github.com/julienschmidt/httprouter" - "github.com/tstranex/u2f" ) type APIConfig struct { @@ -103,9 +102,7 @@ func NewAPIServer(config *APIConfig) http.Handler { srv.POST("/:version/users/:user/ssh/authenticate", srv.withAuth(srv.authenticateSSHUser)) srv.GET("/:version/users/:user/web/sessions/:sid", srv.withAuth(srv.getWebSession)) srv.DELETE("/:version/users/:user/web/sessions/:sid", srv.withAuth(srv.deleteWebSession)) - srv.GET("/:version/signuptokens/:token", srv.withAuth(srv.getSignupTokenData)) - srv.POST("/:version/signuptokens/users", srv.withAuth(srv.createUserWithToken)) - srv.POST("/:version/signuptokens", srv.withAuth(srv.createSignupToken)) + srv.POST("/:version/web/password/token", srv.withRate(srv.withAuth(srv.changePasswordWithToken))) // Servers and presence heartbeat srv.POST("/:version/namespaces/:namespace/nodes", srv.withAuth(srv.upsertNode)) @@ -215,7 +212,6 @@ func NewAPIServer(config *APIConfig) http.Handler { // U2F srv.GET("/:version/u2f/signuptokens/:token", srv.withAuth(srv.getSignupU2FRegisterRequest)) - srv.POST("/:version/u2f/users", srv.withAuth(srv.createUserWithU2FToken)) srv.POST("/:version/u2f/users/:user/sign", srv.withAuth(srv.u2fSignRequest)) srv.GET("/:version/u2f/appid", srv.withAuth(srv.getU2FAppID)) @@ -1123,6 +1119,21 @@ func (s *APIServer) getClusterCACert(auth ClientI, w http.ResponseWriter, r *htt return localCA, nil } +func (s *APIServer) changePasswordWithToken(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { + var req ChangePasswordWithTokenRequest + if err := httplib.ReadJSON(r, &req); err != nil { + return nil, trace.Wrap(err) + } + + webSession, err := auth.ChangePasswordWithToken(r.Context(), req) + if err != nil { + log.Debugf("Failed to change user password with token: %v.", err) + return nil, trace.Wrap(err) + } + + return rawMessage(services.GetWebSessionMarshaler().MarshalWebSession(webSession, services.WithVersion(version))) +} + // getU2FAppID returns the U2F AppID in the auth configuration func (s *APIServer) getU2FAppID(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { cap, err := auth.GetAuthPreference() @@ -1226,26 +1237,6 @@ func (s *APIServer) getSession(auth ClientI, w http.ResponseWriter, r *http.Requ return se, nil } -type getSignupTokenDataResponse struct { - User string `json:"user"` - QRImg []byte `json:"qrimg"` -} - -// getSignupTokenData returns the signup data for a token. -func (s *APIServer) getSignupTokenData(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { - token := p.ByName("token") - - user, otpQRCode, err := auth.GetSignupTokenData(token) - if err != nil { - return nil, trace.Wrap(err) - } - - return &getSignupTokenDataResponse{ - User: user, - QRImg: otpQRCode, - }, nil -} - func (s *APIServer) getSignupU2FRegisterRequest(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { token := p.ByName("token") u2fRegReq, err := auth.GetSignupU2FRegisterRequest(token) @@ -1255,83 +1246,6 @@ func (s *APIServer) getSignupU2FRegisterRequest(auth ClientI, w http.ResponseWri return u2fRegReq, nil } -type createSignupTokenReq struct { - User services.UserV1 `json:"user"` - TTL time.Duration `json:"ttl"` -} - -func (s *APIServer) createSignupToken(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { - var req *createSignupTokenReq - - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - if err := req.User.Check(); err != nil { - return nil, trace.Wrap(err) - } - - token, err := auth.CreateSignupToken(req.User, req.TTL) - if err != nil { - return nil, trace.Wrap(err) - } - - return token, nil -} - -type createUserWithTokenReq struct { - Token string `json:"token"` - Password string `json:"password"` - OTPToken string `json:"otp_token"` -} - -func (s *APIServer) createUserWithToken(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { - var req *createUserWithTokenReq - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - cap, err := auth.GetAuthPreference() - if err != nil { - return nil, trace.Wrap(err) - } - - var webSession services.WebSession - - switch cap.GetSecondFactor() { - case teleport.OFF: - webSession, err = auth.CreateUserWithoutOTP(req.Token, req.Password) - case teleport.OTP, teleport.TOTP, teleport.HOTP: - webSession, err = auth.CreateUserWithOTP(req.Token, req.Password, req.OTPToken) - } - if err != nil { - log.Warningf("failed to create user: %v", err.Error()) - return nil, trace.Wrap(err) - } - - return rawMessage(services.GetWebSessionMarshaler().MarshalWebSession(webSession, services.WithVersion(version))) -} - -type createUserWithU2FTokenReq struct { - Token string `json:"token"` - Password string `json:"password"` - U2FRegisterResponse u2f.RegisterResponse `json:"u2f_register_response"` -} - -func (s *APIServer) createUserWithU2FToken(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { - var req *createUserWithU2FTokenReq - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - sess, err := auth.CreateUserWithU2FToken(req.Token, req.Password, req.U2FRegisterResponse) - if err != nil { - log.Error(err) - return nil, trace.Wrap(err) - } - return rawMessage(services.GetWebSessionMarshaler().MarshalWebSession(sess, services.WithVersion(version))) -} - type upsertOIDCConnectorRawReq struct { Connector json.RawMessage `json:"connector"` TTL time.Duration `json:"ttl"` diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 4525a7b5f6e2f..74ff021d28a25 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -1194,8 +1194,8 @@ func (s *AuthServer) DeleteToken(token string) (err error) { return trace.BadParameter("token %s is statically configured and cannot be removed", token) } } - // delete user token: - if err = s.Identity.DeleteSignupToken(token); err == nil { + // delete reset password token: + if err = s.Identity.DeleteResetPasswordToken(context.TODO(), token); err == nil { return nil } // delete node token: @@ -1221,15 +1221,15 @@ func (s *AuthServer) GetTokens(opts ...services.MarshalOption) (tokens []service if err == nil { tokens = append(tokens, tkns.GetStaticTokens()...) } - // get user tokens: - userTokens, err := s.Identity.GetSignupTokens() + // get reset password tokens: + resetPasswordTokens, err := s.Identity.GetResetPasswordTokens(context.TODO()) if err != nil { return nil, trace.Wrap(err) } - // convert user tokens to machine tokens: - for _, t := range userTokens { + // convert reset password tokens to machine tokens: + for _, t := range resetPasswordTokens { roles := teleport.Roles{teleport.RoleSignup} - tok, err := services.NewProvisionToken(t.Token, roles, t.Expires) + tok, err := services.NewProvisionToken(t.GetName(), roles, t.Expiry()) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 0ac5d6cef9cb8..7f02082837b2d 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -734,13 +734,6 @@ func (a *AuthWithRoles) UpsertTOTP(user string, otpSecret string) error { return a.authServer.UpsertTOTP(user, otpSecret) } -func (a *AuthWithRoles) GetOTPData(user string) (string, []byte, error) { - if err := a.currentUserAction(user); err != nil { - return "", nil, trace.Wrap(err) - } - return a.authServer.GetOTPData(user) -} - func (a *AuthWithRoles) PreAuthenticatedSignIn(user string) (services.WebSession, error) { if err := a.currentUserAction(user); err != nil { return nil, trace.Wrap(err) @@ -1041,41 +1034,38 @@ func (a *AuthWithRoles) GenerateUserCerts(ctx context.Context, req proto.UserCer }, nil } -func (a *AuthWithRoles) CreateSignupToken(user services.UserV1, ttl time.Duration) (token string, e error) { - if err := a.action(defaults.Namespace, services.KindUser, services.VerbCreate); err != nil { - return "", trace.Wrap(err) - } - return a.authServer.CreateSignupToken(user, ttl) -} - -func (a *AuthWithRoles) GetSignupTokenData(token string) (user string, otpQRCode []byte, err error) { +func (a *AuthWithRoles) GetSignupU2FRegisterRequest(token string) (u2fRegisterRequest *u2f.RegisterRequest, e error) { // signup token are their own authz resource - return a.authServer.GetSignupTokenData(token) + return a.authServer.CreateSignupU2FRegisterRequest(token) } -func (a *AuthWithRoles) GetSignupToken(token string) (*services.SignupToken, error) { - // signup token are their own authz resource - return a.authServer.GetSignupToken(token) -} +func (a *AuthWithRoles) CreateResetPasswordToken(ctx context.Context, req CreateResetPasswordTokenRequest) (services.ResetPasswordToken, error) { + if err := a.action(defaults.Namespace, services.KindUser, services.VerbUpdate); err != nil { + return nil, trace.Wrap(err) + } -func (a *AuthWithRoles) GetSignupU2FRegisterRequest(token string) (u2fRegisterRequest *u2f.RegisterRequest, e error) { - // signup token are their own authz resource - return a.authServer.CreateSignupU2FRegisterRequest(token) + a.EmitAuditEvent(events.ResetPasswordTokenCreated, events.EventFields{ + events.ResetPasswordTokenFor: req.Name, + events.ResetPasswordTokenTTL: req.TTL.String(), + events.EventUser: a.user.GetName(), + }) + + return a.authServer.CreateResetPasswordToken(ctx, req) } -func (a *AuthWithRoles) CreateUserWithOTP(token, password, otpToken string) (services.WebSession, error) { +func (a *AuthWithRoles) GetResetPasswordToken(ctx context.Context, tokenID string) (services.ResetPasswordToken, error) { // tokens are their own authz mechanism, no need to double check - return a.authServer.CreateUserWithOTP(token, password, otpToken) + return a.authServer.GetResetPasswordToken(ctx, tokenID) } -func (a *AuthWithRoles) CreateUserWithoutOTP(token string, password string) (services.WebSession, error) { +func (a *AuthWithRoles) RotateResetPasswordTokenSecrets(ctx context.Context, tokenID string) (services.ResetPasswordTokenSecrets, error) { // tokens are their own authz mechanism, no need to double check - return a.authServer.CreateUserWithoutOTP(token, password) + return a.authServer.RotateResetPasswordTokenSecrets(ctx, tokenID) } -func (a *AuthWithRoles) CreateUserWithU2FToken(token string, password string, u2fRegisterResponse u2f.RegisterResponse) (services.WebSession, error) { - // signup tokens are their own authz resource - return a.authServer.CreateUserWithU2FToken(token, password, u2fRegisterResponse) +func (a *AuthWithRoles) ChangePasswordWithToken(ctx context.Context, req ChangePasswordWithTokenRequest) (services.WebSession, error) { + // Token is it's own authentication, no need to double check. + return a.authServer.ChangePasswordWithToken(ctx, req) } func (a *AuthWithRoles) UpsertUser(u services.User) error { diff --git a/lib/auth/clt.go b/lib/auth/clt.go index 1cff25788c9b6..31877a44b156b 100644 --- a/lib/auth/clt.go +++ b/lib/auth/clt.go @@ -686,7 +686,7 @@ func (c *Client) GetToken(token string) (services.ProvisionToken, error) { } // DeleteToken deletes a given provisioning token on the auth server (CA). It -// could be a user token or a machine token +// could be a reset password token or a machine token func (c *Client) DeleteToken(token string) error { _, err := c.Delete(c.Endpoint("tokens", token)) return trace.Wrap(err) @@ -1577,41 +1577,6 @@ func (c *Client) GenerateHostCert( return []byte(cert), nil } -// CreateSignupToken creates one time token for creating account for the user -// For each token it creates username and otp generator -func (c *Client) CreateSignupToken(user services.UserV1, ttl time.Duration) (string, error) { - if err := user.Check(); err != nil { - return "", trace.Wrap(err) - } - out, err := c.PostJSON(c.Endpoint("signuptokens"), createSignupTokenReq{ - User: user, - TTL: ttl, - }) - if err != nil { - return "", trace.Wrap(err) - } - var token string - if err := json.Unmarshal(out.Bytes(), &token); err != nil { - return "", trace.Wrap(err) - } - return token, nil -} - -// GetSignupTokenData returns token data for a valid token -func (c *Client) GetSignupTokenData(token string) (user string, otpQRCode []byte, e error) { - out, err := c.Get(c.Endpoint("signuptokens", token), url.Values{}) - if err != nil { - return "", nil, err - } - - var tokenData getSignupTokenDataResponse - if err := json.Unmarshal(out.Bytes(), &tokenData); err != nil { - return "", nil, err - } - - return tokenData.User, tokenData.QRImg, nil -} - // GenerateUserCerts takes the public key in the OpenSSH `authorized_keys` plain // text format, signs it using User Certificate Authority signing key and // returns the resulting certificates. @@ -1640,41 +1605,9 @@ func (c *Client) GetSignupU2FRegisterRequest(token string) (u2fRegisterRequest * return &u2fRegReq, nil } -// CreateUserWithOTP creates account with provided token and password. -// Account username and OTP key are taken from token data. -// Deletes token after account creation. -func (c *Client) CreateUserWithOTP(token, password, otpToken string) (services.WebSession, error) { - out, err := c.PostJSON(c.Endpoint("signuptokens", "users"), createUserWithTokenReq{ - Token: token, - Password: password, - OTPToken: otpToken, - }) - if err != nil { - return nil, trace.Wrap(err) - } - return services.GetWebSessionMarshaler().UnmarshalWebSession(out.Bytes()) -} - -// CreateUserWithoutOTP validates a given token creates a user -// with the given password and deletes the token afterwards. -func (c *Client) CreateUserWithoutOTP(token string, password string) (services.WebSession, error) { - out, err := c.PostJSON(c.Endpoint("signuptokens", "users"), createUserWithTokenReq{ - Token: token, - Password: password, - }) - if err != nil { - return nil, trace.Wrap(err) - } - return services.GetWebSessionMarshaler().UnmarshalWebSession(out.Bytes()) -} - -// CreateUserWithU2FToken creates user account with provided token and U2F sign response -func (c *Client) CreateUserWithU2FToken(token string, password string, u2fRegisterResponse u2f.RegisterResponse) (services.WebSession, error) { - out, err := c.PostJSON(c.Endpoint("u2f", "users"), createUserWithU2FTokenReq{ - Token: token, - Password: password, - U2FRegisterResponse: u2fRegisterResponse, - }) +// ChangePasswordWithToken changes user password with ResetPasswordToken +func (c *Client) ChangePasswordWithToken(ctx context.Context, req ChangePasswordWithTokenRequest) (services.WebSession, error) { + out, err := c.PostJSON(c.Endpoint("web", "password", "token"), req) if err != nil { return nil, trace.Wrap(err) } @@ -2572,6 +2505,57 @@ func (c *Client) CreateAccessRequest(ctx context.Context, req services.AccessReq return nil } +func (c *Client) RotateResetPasswordTokenSecrets(ctx context.Context, tokenID string) (services.ResetPasswordTokenSecrets, error) { + clt, err := c.grpc() + if err != nil { + return nil, trace.Wrap(err) + } + + secrets, err := clt.RotateResetPasswordTokenSecrets(ctx, &proto.RotateResetPasswordTokenSecretsRequest{ + TokenID: tokenID, + }) + if err != nil { + return nil, trail.FromGRPC(err) + } + + return secrets, nil +} + +func (c *Client) GetResetPasswordToken(ctx context.Context, tokenID string) (services.ResetPasswordToken, error) { + clt, err := c.grpc() + if err != nil { + return nil, trace.Wrap(err) + } + + token, err := clt.GetResetPasswordToken(ctx, &proto.GetResetPasswordTokenRequest{ + TokenID: tokenID, + }) + if err != nil { + return nil, trail.FromGRPC(err) + } + + return token, nil +} + +// CreateResetPasswordToken creates reset password token +func (c *Client) CreateResetPasswordToken(ctx context.Context, req CreateResetPasswordTokenRequest) (services.ResetPasswordToken, error) { + clt, err := c.grpc() + if err != nil { + return nil, trace.Wrap(err) + } + + token, err := clt.CreateResetPasswordToken(ctx, &proto.CreateResetPasswordTokenRequest{ + Name: req.Name, + TTL: proto.Duration(req.TTL), + Type: req.Type, + }) + if err != nil { + return nil, trail.FromGRPC(err) + } + + return token, nil +} + func (c *Client) DeleteAccessRequest(ctx context.Context, reqID string) error { clt, err := c.grpc() if err != nil { @@ -2680,9 +2664,6 @@ type IdentityService interface { // GetSignupU2FRegisterRequest generates sign request for user trying to sign up with invite token GetSignupU2FRegisterRequest(token string) (*u2f.RegisterRequest, error) - // CreateUserWithU2FToken creates user account with provided token and U2F sign response - CreateUserWithU2FToken(token string, password string, u2fRegisterResponse u2f.RegisterResponse) (services.WebSession, error) - // GetUser returns user by name GetUser(name string, withSecrets bool) (services.User, error) @@ -2701,15 +2682,6 @@ type IdentityService interface { // CheckPassword checks if the suplied web access password is valid. CheckPassword(user string, password []byte, otpToken string) error - // CreateUserWithOTP creates account with provided token and password. - // Account username and OTP key are taken from token data. - // Deletes token after account creation. - CreateUserWithOTP(token, password, otpToken string) (services.WebSession, error) - - // CreateUserWithoutOTP validates a given token creates a user - // with the given password and deletes the token afterwards. - CreateUserWithoutOTP(token string, password string) (services.WebSession, error) - // GenerateToken creates a special provisioning token for a new SSH server // that is valid for ttl period seconds. // @@ -2735,15 +2707,20 @@ type IdentityService interface { // returns the resulting certificates. GenerateUserCerts(ctx context.Context, req proto.UserCertsRequest) (*proto.Certs, error) - // GetSignupTokenData returns token data for a valid token - GetSignupTokenData(token string) (user string, otpQRCode []byte, e error) - - // CreateSignupToken creates one time token for creating account for the user - // For each token it creates username and OTP key - CreateSignupToken(user services.UserV1, ttl time.Duration) (string, error) - // DeleteAllUsers deletes all users DeleteAllUsers() error + + // CreateResetPasswordToken creates a new user reset token + CreateResetPasswordToken(ctx context.Context, req CreateResetPasswordTokenRequest) (services.ResetPasswordToken, error) + + // ChangePasswordWithToken changes password with token + ChangePasswordWithToken(ctx context.Context, req ChangePasswordWithTokenRequest) (services.WebSession, error) + + // GetResetPasswordToken returns token + GetResetPasswordToken(ctx context.Context, username string) (services.ResetPasswordToken, error) + + // RotateResetPasswordTokenSecrets rotates token secrets for a given tokenID + RotateResetPasswordTokenSecrets(ctx context.Context, tokenID string) (services.ResetPasswordTokenSecrets, error) } // ProvisioningService is a service in control @@ -2756,7 +2733,7 @@ type ProvisioningService interface { GetToken(token string) (services.ProvisionToken, error) // DeleteToken deletes a given provisioning token on the auth server (CA). It - // could be a user token or a machine token + // could be a reset password token or a machine token DeleteToken(token string) error // DeleteAllTokens deletes all provisioning tokens diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index f07c78bad55d2..f0efcbb171ad3 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -21,6 +21,7 @@ import ( "io" "net/http" "strings" + "time" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/auth/proto" @@ -246,6 +247,84 @@ func (g *GRPCServer) SetAccessRequestState(ctx context.Context, req *proto.Reque return &empty.Empty{}, nil } +func (g *GRPCServer) CreateResetPasswordToken(ctx context.Context, req *proto.CreateResetPasswordTokenRequest) (*services.ResetPasswordTokenV3, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + if req == nil { + req = &proto.CreateResetPasswordTokenRequest{} + } + + token, err := auth.CreateResetPasswordToken(ctx, CreateResetPasswordTokenRequest{ + Name: req.Name, + TTL: time.Duration(req.TTL), + Type: req.Type, + }) + if err != nil { + return nil, trace.Wrap(err) + } + + r, ok := token.(*services.ResetPasswordTokenV3) + if !ok { + err = trace.BadParameter("unexpected ResetPasswordToken type %T", token) + return nil, trail.ToGRPC(err) + } + + return r, nil +} + +func (g *GRPCServer) RotateResetPasswordTokenSecrets(ctx context.Context, req *proto.RotateResetPasswordTokenSecretsRequest) (*services.ResetPasswordTokenSecretsV3, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + tokenID := "" + if req != nil { + tokenID = req.TokenID + } + + secrets, err := auth.RotateResetPasswordTokenSecrets(ctx, tokenID) + if err != nil { + return nil, trail.ToGRPC(err) + } + + r, ok := secrets.(*services.ResetPasswordTokenSecretsV3) + if !ok { + err = trace.BadParameter("unexpected ResetPasswordTokenSecrets type %T", secrets) + return nil, trail.ToGRPC(err) + } + + return r, nil +} + +func (g *GRPCServer) GetResetPasswordToken(ctx context.Context, req *proto.GetResetPasswordTokenRequest) (*services.ResetPasswordTokenV3, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + tokenID := "" + if req != nil { + tokenID = req.TokenID + } + + token, err := auth.GetResetPasswordToken(ctx, tokenID) + if err != nil { + return nil, trail.ToGRPC(err) + } + + r, ok := token.(*services.ResetPasswordTokenV3) + if !ok { + err = trace.BadParameter("unexpected ResetPasswordToken type %T", token) + return nil, trail.ToGRPC(err) + } + + return r, nil +} + type grpcContext struct { *AuthContext *AuthWithRoles diff --git a/lib/auth/methods.go b/lib/auth/methods.go index 9d15929d26c35..8cdc6a77078cb 100644 --- a/lib/auth/methods.go +++ b/lib/auth/methods.go @@ -184,22 +184,21 @@ func (s *AuthServer) AuthenticateWebUser(req AuthenticateUserRequest) (services. } return session, nil } + if err := s.AuthenticateUser(req); err != nil { return nil, trace.Wrap(err) } + user, err := s.GetUser(req.Username, false) if err != nil { return nil, trace.Wrap(err) } - // It's safe to extract the roles and traits directly from services.User as - // this endpoint is only used for local accounts. - sess, err := s.NewWebSession(req.Username, user.GetRoles(), user.GetTraits()) + + sess, err := s.createUserWebSession(user) if err != nil { return nil, trace.Wrap(err) } - if err := s.UpsertWebSession(req.Username, sess); err != nil { - return nil, trace.Wrap(err) - } + sess, err = services.GetWebSessionMarshaler().GenerateWebSession(sess) if err != nil { return nil, trace.Wrap(err) @@ -365,4 +364,19 @@ func (s *AuthServer) emitNoLocalAuthEvent(username string) { s.IAuditLog.EmitAuditEvent(events.AuthAttemptFailure, fields) } +func (s *AuthServer) createUserWebSession(user services.User) (services.WebSession, error) { + // It's safe to extract the roles and traits directly from services.User as this method + // is only used for local accounts. + sess, err := s.NewWebSession(user.GetName(), user.GetRoles(), user.GetTraits()) + if err != nil { + return nil, trace.Wrap(err) + } + err = s.UpsertWebSession(user.GetName(), sess) + if err != nil { + return nil, trace.Wrap(err) + } + + return sess, nil +} + const noLocalAuth = "local auth disabled" diff --git a/lib/auth/new_web_user.go b/lib/auth/new_web_user.go deleted file mode 100644 index aa5c4f2e189dc..0000000000000 --- a/lib/auth/new_web_user.go +++ /dev/null @@ -1,467 +0,0 @@ -/* -Copyright 2015 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 auth implements certificate signing authority and access control server -// Authority server is composed of several parts: -// -// * Authority server itself that implements signing and acl logic -// * HTTP server wrapper for authority server -// * HTTP client wrapper -// -package auth - -import ( - "bytes" - "image/png" - "time" - - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/lib/defaults" - "github.com/gravitational/teleport/lib/events" - "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/teleport/lib/utils" - - "github.com/gravitational/trace" - "github.com/pquerna/otp/totp" - - "github.com/tstranex/u2f" -) - -// CreateSignupToken creates one time token for creating account for the user -// For each token it creates username and otp generator -func (s *AuthServer) CreateSignupToken(userv1 services.UserV1, ttl time.Duration) (string, error) { - clusterConfig, err := s.GetClusterConfig() - if err != nil { - return "", trace.Wrap(err) - } - if clusterConfig.GetLocalAuth() == false { - s.emitNoLocalAuthEvent(userv1.V2().GetName()) - return "", trace.AccessDenied(noLocalAuth) - } - - user := userv1.V2() - if err := user.Check(); err != nil { - return "", trace.Wrap(err) - } - - if ttl > defaults.MaxSignupTokenTTL { - return "", trace.BadParameter("failed to invite user: maximum signup token TTL is %v hours", int(defaults.MaxSignupTokenTTL/time.Hour)) - } - - // make sure that connectors actually exist - for _, id := range user.GetOIDCIdentities() { - if err := id.Check(); err != nil { - return "", trace.Wrap(err) - } - if _, err := s.GetOIDCConnector(id.ConnectorID, false); err != nil { - return "", trace.Wrap(err) - } - } - - for _, id := range user.GetSAMLIdentities() { - if err := id.Check(); err != nil { - return "", trace.Wrap(err) - } - if _, err := s.GetSAMLConnector(id.ConnectorID, false); err != nil { - return "", trace.Wrap(err) - } - } - - // TODO(rjones): TOCTOU, instead try to create signup token for user and fail - // when unable to. - _, err = s.GetPasswordHash(user.GetName()) - if err == nil { - return "", trace.BadParameter("user '%s' already exists", user.GetName()) - } - - token, err := utils.CryptoRandomHex(TokenLenBytes) - if err != nil { - return "", trace.Wrap(err) - } - - // This OTP secret and QR code are never actually used. The OTP secret and - // QR code are rotated every time the signup link is show to the user, see - // the "GetSignupTokenData" function for details on why this is done. We - // generate a OTP token because it causes no harm and makes tests easier to - // write. - accountName := user.GetName() + "@" + s.AuthServiceName - otpKey, otpQRCode, err := s.initializeTOTP(accountName) - if err != nil { - return "", trace.Wrap(err) - } - - // create and upsert signup token - tokenData := services.SignupToken{ - Token: token, - User: userv1, - OTPKey: otpKey, - OTPQRCode: otpQRCode, - } - - if ttl == 0 || ttl > defaults.MaxSignupTokenTTL { - ttl = defaults.SignupTokenTTL - } - - err = s.UpsertSignupToken(token, tokenData, ttl) - if err != nil { - return "", trace.Wrap(err) - } - - log.Infof("[AUTH API] created the signup token for %q", user) - return token, nil -} - -// initializeTOTP creates TOTP algorithm and returns the key and QR code. -func (s *AuthServer) initializeTOTP(accountName string) (key string, qr []byte, err error) { - // create totp key - otpKey, err := totp.Generate(totp.GenerateOpts{ - Issuer: "Teleport", - AccountName: accountName, - }) - if err != nil { - return "", nil, trace.Wrap(err) - } - - // create QR code - var otpQRBuf bytes.Buffer - otpImage, err := otpKey.Image(456, 456) - if err != nil { - return "", nil, trace.Wrap(err) - } - png.Encode(&otpQRBuf, otpImage) - - return otpKey.Secret(), otpQRBuf.Bytes(), nil -} - -// rotateAndFetchSignupToken rotates the signup token everytime it's fetched. -// This ensures that an attacker that gains the signup link can not view it, -// extract the OTP key from the QR code, then allow the user to signup with -// the same OTP token. -func (s *AuthServer) rotateAndFetchSignupToken(token string) (*services.SignupToken, error) { - var err error - - // Fetch original signup token. - st, err := s.GetSignupToken(token) - if err != nil { - return nil, trace.Wrap(err) - } - - // Generate and set new OTP code for user in *services.SignupToken. - accountName := st.User.V2().GetName() + "@" + s.AuthServiceName - st.OTPKey, st.OTPQRCode, err = s.initializeTOTP(accountName) - if err != nil { - return nil, trace.Wrap(err) - } - - // Upsert token into backend. - err = s.UpsertSignupToken(token, *st, st.Expires.Sub(s.clock.Now())) - if err != nil { - return nil, trace.Wrap(err) - } - - return st, nil -} - -// GetSignupTokenData returns token data (username and QR code bytes) for a -// valid signup token. -func (s *AuthServer) GetSignupTokenData(token string) (user string, qrCode []byte, err error) { - // Rotate OTP secret before the signup data is fetched (signup page is - // rendered). This mitigates attacks where an attacker just views the signup - // link, extracts the OTP secret from the QR code, then closes the window. - // Then when the user signs up later, the attacker has access to the OTP - // secret. - st, err := s.rotateAndFetchSignupToken(token) - if err != nil { - return "", nil, trace.Wrap(err) - } - - // TODO(rjones): Remove this check and use compare and swap in the Create* - // functions below. It's a TOCTOU bug in the making: - // https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use - _, err = s.GetPasswordHash(st.User.Name) - if err == nil { - return "", nil, trace.Errorf("user %q already exists", st.User.Name) - } - - return st.User.Name, st.OTPQRCode, nil -} - -func (s *AuthServer) CreateSignupU2FRegisterRequest(token string) (u2fRegisterRequest *u2f.RegisterRequest, e error) { - cap, err := s.GetAuthPreference() - if err != nil { - return nil, trace.Wrap(err) - } - - universalSecondFactor, err := cap.GetU2F() - if err != nil { - return nil, trace.Wrap(err) - } - - tokenData, err := s.GetSignupToken(token) - if err != nil { - return nil, trace.Wrap(err) - } - - _, err = s.GetPasswordHash(tokenData.User.Name) - if err == nil { - return nil, trace.AlreadyExists("user %q already exists", tokenData.User.Name) - } - - c, err := u2f.NewChallenge(universalSecondFactor.AppID, universalSecondFactor.Facets) - if err != nil { - return nil, trace.Wrap(err) - } - - request := c.RegisterRequest() - - err = s.UpsertU2FRegisterChallenge(token, c) - if err != nil { - return nil, trace.Wrap(err) - } - - return request, nil -} - -// CreateUserWithOTP creates account with provided token and password. -// Account username and hotp generator are taken from token data. -// Deletes token after account creation. -func (s *AuthServer) CreateUserWithOTP(token string, password string, otpToken string) (services.WebSession, error) { - clusterConfig, err := s.GetClusterConfig() - if err != nil { - return nil, trace.Wrap(err) - } - if clusterConfig.GetLocalAuth() == false { - s.emitNoLocalAuthEvent("") - return nil, trace.AccessDenied(noLocalAuth) - } - - tokenData, err := s.GetSignupToken(token) - if err != nil { - log.Debugf("failed to get signup token: %v", err) - return nil, trace.AccessDenied("expired or incorrect signup token") - } - - err = s.UpsertTOTP(tokenData.User.Name, tokenData.OTPKey) - if err != nil { - return nil, trace.Wrap(err) - } - - err = s.CheckOTP(tokenData.User.Name, otpToken) - if err != nil { - log.Debugf("failed to validate a token: %v", err) - return nil, trace.AccessDenied("failed to validate a token") - } - - err = s.UpsertPassword(tokenData.User.Name, []byte(password)) - if err != nil { - return nil, trace.Wrap(err) - } - - // create services.User and services.WebSession - webSession, err := s.createUserAndSession(tokenData) - if err != nil { - return nil, trace.Wrap(err) - } - - return webSession, nil -} - -// CreateUserWithoutOTP creates an account with the provided password and deletes the token afterwards. -func (s *AuthServer) CreateUserWithoutOTP(token string, password string) (services.WebSession, error) { - clusterConfig, err := s.GetClusterConfig() - if err != nil { - return nil, trace.Wrap(err) - } - if clusterConfig.GetLocalAuth() == false { - s.emitNoLocalAuthEvent("") - return nil, trace.AccessDenied(noLocalAuth) - } - - authPreference, err := s.GetAuthPreference() - if err != nil { - return nil, trace.Wrap(err) - } - if authPreference.GetSecondFactor() != teleport.OFF { - return nil, trace.AccessDenied("missing second factor") - } - tokenData, err := s.GetSignupToken(token) - if err != nil { - log.Warningf("failed to get signup token: %v", err) - return nil, trace.AccessDenied("expired or incorrect signup token") - } - - err = s.UpsertPassword(tokenData.User.Name, []byte(password)) - if err != nil { - return nil, trace.Wrap(err) - } - - // create services.User and services.WebSession - webSession, err := s.createUserAndSession(tokenData) - if err != nil { - return nil, trace.Wrap(err) - } - - return webSession, nil -} - -func (s *AuthServer) CreateUserWithU2FToken(token string, password string, response u2f.RegisterResponse) (services.WebSession, error) { - clusterConfig, err := s.GetClusterConfig() - if err != nil { - return nil, trace.Wrap(err) - } - if clusterConfig.GetLocalAuth() == false { - s.emitNoLocalAuthEvent("") - return nil, trace.AccessDenied(noLocalAuth) - } - - // before trying to create a user, see U2F is actually setup on the backend - cap, err := s.GetAuthPreference() - if err != nil { - return nil, trace.Wrap(err) - } - _, err = cap.GetU2F() - if err != nil { - return nil, trace.Wrap(err) - } - - tokenData, err := s.GetSignupToken(token) - if err != nil { - log.Warningf("failed to get signup token: %v", err) - return nil, trace.AccessDenied("expired or incorrect signup token") - } - - challenge, err := s.GetU2FRegisterChallenge(token) - if err != nil { - return nil, trace.Wrap(err) - } - - reg, err := u2f.Register(response, *challenge, &u2f.Config{SkipAttestationVerify: true}) - if err != nil { - log.Error(trace.DebugReport(err)) - return nil, trace.Wrap(err) - } - - err = s.UpsertU2FRegistration(tokenData.User.Name, reg) - if err != nil { - return nil, trace.Wrap(err) - } - err = s.UpsertU2FRegistrationCounter(tokenData.User.Name, 0) - if err != nil { - return nil, trace.Wrap(err) - } - - err = s.UpsertPassword(tokenData.User.Name, []byte(password)) - if err != nil { - return nil, trace.Wrap(err) - } - - // create services.User and services.WebSession - webSession, err := s.createUserAndSession(tokenData) - if err != nil { - return nil, trace.Wrap(err) - } - - return webSession, nil -} - -// createUserAndSession takes a signup token and creates services.User (either -// with the passed in roles, or if no role, the default role) and -// services.WebSession in the backend and returns the new services.WebSession. -func (a *AuthServer) createUserAndSession(stoken *services.SignupToken) (services.WebSession, error) { - // extract user from signup token. if no roles have been passed along, create - // user with default role. note: during the conversion from services.UserV1 - // to services.UserV2 we convert allowed logins to traits. - user := stoken.User.V2() - if len(user.GetRoles()) == 0 { - user.SetRoles([]string{teleport.AdminRoleName}) - } - - // upsert user into the backend - err := a.UpsertUser(user) - if err != nil { - return nil, trace.Wrap(err) - } - log.Infof("[AUTH] Created user: %v", user) - - // remove the token once the user has been created - err = a.DeleteSignupToken(stoken.Token) - if err != nil { - return nil, trace.Wrap(err) - } - - // It's safe to extract the roles and traits directly from services.User as - // this endpoint is only used for local accounts. - sess, err := a.NewWebSession(user.GetName(), user.GetRoles(), user.GetTraits()) - if err != nil { - return nil, trace.Wrap(err) - } - err = a.UpsertWebSession(user.GetName(), sess) - if err != nil { - return nil, trace.Wrap(err) - } - - return sess, nil -} - -func (a *AuthServer) UpsertUser(user services.User) error { - err := a.Identity.UpsertUser(user) - if err != nil { - return trace.Wrap(err) - } - - // If the user was successfully upserted, emit an event. - var connectorName string - if user.GetCreatedBy().Connector == nil { - connectorName = teleport.Local - } else { - connectorName = user.GetCreatedBy().Connector.ID - } - a.EmitAuditEvent(events.UserUpdate, events.EventFields{ - events.EventUser: user.GetName(), - events.UserExpires: user.Expiry(), - events.UserRoles: user.GetRoles(), - events.UserConnector: connectorName, - }) - - return 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.GetName()); err != nil { - if !trace.IsNotFound(err) { - return trace.Wrap(err) - } - } - } - - err = a.Identity.DeleteUser(user) - if err != nil { - return trace.Wrap(err) - } - - // If the user was successfully deleted, emit an event. - a.EmitAuditEvent(events.UserDelete, events.EventFields{ - events.EventUser: user, - }) - - return nil -} diff --git a/lib/auth/password.go b/lib/auth/password.go index d89d69ee9bc75..e7503f9949230 100644 --- a/lib/auth/password.go +++ b/lib/auth/password.go @@ -1,6 +1,7 @@ package auth import ( + "context" "crypto/subtle" "golang.org/x/crypto/bcrypt" @@ -10,6 +11,7 @@ import ( "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/trace" + "github.com/tstranex/u2f" "github.com/pquerna/otp" "github.com/pquerna/otp/totp" @@ -17,6 +19,55 @@ import ( var fakePasswordHash = []byte(`$2a$10$Yy.e6BmS2SrGbBDsyDLVkOANZmvjjMR890nUGSXFJHBXWzxe7T44m`) +// ChangePasswordWithTokenRequest defines a request to change user password +type ChangePasswordWithTokenRequest struct { + // SecondFactorToken is 2nd factor token value + SecondFactorToken string `json:"second_factor_token"` + // TokenID is this token ID + TokenID string `json:"token"` + // Password is user password + Password []byte `json:"password"` + // U2FRegisterResponse is U2F register response + U2FRegisterResponse u2f.RegisterResponse `json:"u2f_register_response"` +} + +// ChangePasswordWithToken changes password with token +func (s *AuthServer) ChangePasswordWithToken(ctx context.Context, req ChangePasswordWithTokenRequest) (services.WebSession, error) { + user, err := s.changePasswordWithToken(ctx, req) + if err != nil { + return nil, trace.Wrap(err) + } + + sess, err := s.createUserWebSession(user) + if err != nil { + return nil, trace.Wrap(err) + } + + return sess, nil +} + +// ResetPassword securely generates a new random password and assigns it to user. +// This method is used to invalidate existing user password during password +// reset process. +func (s *AuthServer) ResetPassword(username string) (string, error) { + user, err := s.GetUser(username, false) + if err != nil { + return "", trace.Wrap(err) + } + + password, err := utils.CryptoRandomHex(defaults.ResetPasswordLength) + if err != nil { + return "", trace.Wrap(err) + } + + err = s.UpsertPassword(user.GetName(), []byte(password)) + if err != nil { + return "", trace.Wrap(err) + } + + return password, nil +} + // ChangePassword changes user passsword func (s *AuthServer) ChangePassword(req services.ChangePasswordReq) error { // validate new password @@ -165,8 +216,39 @@ func (s *AuthServer) CheckOTP(user string, otpToken string) error { return nil } +// CreateSignupU2FRegisterRequest creates U2F requests +func (s *AuthServer) CreateSignupU2FRegisterRequest(tokenID string) (u2fRegisterRequest *u2f.RegisterRequest, e error) { + cap, err := s.GetAuthPreference() + if err != nil { + return nil, trace.Wrap(err) + } + + universalSecondFactor, err := cap.GetU2F() + if err != nil { + return nil, trace.Wrap(err) + } + + _, err = s.GetResetPasswordToken(context.TODO(), tokenID) + if err != nil { + return nil, trace.Wrap(err) + } + + c, err := u2f.NewChallenge(universalSecondFactor.AppID, universalSecondFactor.Facets) + if err != nil { + return nil, trace.Wrap(err) + } + + err = s.UpsertU2FRegisterChallenge(tokenID, c) + if err != nil { + return nil, trace.Wrap(err) + } + + request := c.RegisterRequest() + return request, nil +} + // getOTPType returns the type of OTP token used, HOTP or TOTP. -// Deprecated: Remove this method once HOTP support has been removed. +// Deprecated: Remove this method once HOTP support has been removed from Gravity. func (s *AuthServer) getOTPType(user string) (string, error) { _, err := s.GetHOTP(user) if err != nil { @@ -178,23 +260,115 @@ func (s *AuthServer) getOTPType(user string) (string, error) { return teleport.HOTP, nil } -// GetOTPData returns the OTP Key, Key URL, and the QR code. -func (s *AuthServer) GetOTPData(user string) (string, []byte, error) { - // get otp key from backend - otpSecret, err := s.GetTOTP(user) +func (s *AuthServer) changePasswordWithToken(ctx context.Context, req ChangePasswordWithTokenRequest) (services.User, error) { + // Get cluster configuration and check if local auth is allowed. + clusterConfig, err := s.GetClusterConfig() + if err != nil { + return nil, trace.Wrap(err) + } + if clusterConfig.GetLocalAuth() == false { + return nil, trace.AccessDenied(noLocalAuth) + } + + err = services.VerifyPassword(req.Password) + if err != nil { + return nil, trace.Wrap(err) + } + + // Check if token exists. + token, err := s.GetResetPasswordToken(ctx, req.TokenID) + if err != nil { + return nil, trace.Wrap(err) + } + + if token.Expiry().Before(s.clock.Now().UTC()) { + return nil, trace.BadParameter("expired token") + } + + err = s.changeUserSecondFactor(req, token) if err != nil { - return "", nil, trace.Wrap(err) + return nil, trace.Wrap(err) } - // create otp url - params := map[string][]byte{"secret": []byte(otpSecret)} - otpURL := utils.GenerateOTPURL("totp", user, params) + username := token.GetUser() + // Delete this token first to minimize the chances + // of partially updated user with still valid token. + err = s.deleteResetPasswordTokens(ctx, username) + if err != nil { + return nil, trace.Wrap(err) + } - // create the qr code - otpQR, err := utils.GenerateQRCode(otpURL) + // Set a new password. + err = s.UpsertPassword(username, []byte(req.Password)) if err != nil { - return "", nil, trace.Wrap(err) + return nil, trace.Wrap(err) + } + + user, err := s.GetUser(username, false) + if err != nil { + return nil, trace.Wrap(err) + } + + return user, nil +} + +func (s *AuthServer) changeUserSecondFactor(req ChangePasswordWithTokenRequest, ResetPasswordToken services.ResetPasswordToken) error { + username := ResetPasswordToken.GetUser() + cap, err := s.GetAuthPreference() + if err != nil { + return trace.Wrap(err) + } + + switch cap.GetSecondFactor() { + case teleport.OFF: + return nil + case teleport.OTP, teleport.TOTP, teleport.HOTP: + secrets, err := s.Identity.GetResetPasswordTokenSecrets(context.TODO(), req.TokenID) + if err != nil { + return trace.Wrap(err) + } + + // TODO: create a separate method to validate TOTP without inserting it first + err = s.UpsertTOTP(username, secrets.GetOTPKey()) + if err != nil { + return trace.Wrap(err) + } + + err = s.CheckOTP(username, req.SecondFactorToken) + if err != nil { + return trace.Wrap(err) + } + + return nil + case teleport.U2F: + _, err = cap.GetU2F() + if err != nil { + return trace.Wrap(err) + } + + challenge, err := s.GetU2FRegisterChallenge(req.TokenID) + if err != nil { + return trace.Wrap(err) + } + + u2fRes := req.U2FRegisterResponse + reg, err := u2f.Register(u2fRes, *challenge, &u2f.Config{SkipAttestationVerify: true}) + if err != nil { + return trace.Wrap(err) + } + + err = s.UpsertU2FRegistration(username, reg) + if err != nil { + return trace.Wrap(err) + } + + err = s.UpsertU2FRegistrationCounter(username, 0) + if err != nil { + return trace.Wrap(err) + } + + return nil } - return otpURL, otpQR, nil + return trace.BadParameter("unknown second factor type %q", cap.GetSecondFactor()) } diff --git a/lib/auth/password_test.go b/lib/auth/password_test.go index 673952241de50..22aae0862d42c 100644 --- a/lib/auth/password_test.go +++ b/lib/auth/password_test.go @@ -76,6 +76,14 @@ func (s *PasswordSuite) SetUpTest(c *C) { err = s.a.SetClusterName(clusterName) c.Assert(err, IsNil) + clusterConfig, err := services.NewClusterConfig(services.ClusterConfigSpecV3{ + LocalAuth: services.NewBool(true), + }) + c.Assert(err, IsNil) + + err = s.a.SetClusterConfig(clusterConfig) + c.Assert(err, IsNil) + // set static tokens staticTokens, err := services.NewStaticTokens(services.StaticTokensSpecV2{ StaticTokens: []services.ProvisionTokenV1{}, @@ -171,6 +179,162 @@ func (s *PasswordSuite) TestChangePasswordWithOTP(c *C) { c.Assert(err, IsNil) } +func (s *PasswordSuite) TestChangePasswordWithToken(c *C) { + authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OFF, + }) + c.Assert(err, IsNil) + + err = s.a.SetAuthPreference(authPreference) + c.Assert(err, IsNil) + + username := "joe@example.com" + password := []byte("qweqweqwe") + _, _, err = CreateUserAndRole(s.a, username, []string{username}) + c.Assert(err, IsNil) + + token, err := s.a.CreateResetPasswordToken(context.TODO(), CreateResetPasswordTokenRequest{ + Name: username, + }) + c.Assert(err, IsNil) + + _, err = s.a.changePasswordWithToken(context.TODO(), ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + Password: password, + }) + c.Assert(err, IsNil) + + // password should be updated + err = s.a.CheckPasswordWOToken(username, password) + c.Assert(err, IsNil) +} + +func (s *PasswordSuite) TestChangePasswordWithTokenOTP(c *C) { + authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OTP, + }) + c.Assert(err, IsNil) + + err = s.a.SetAuthPreference(authPreference) + c.Assert(err, IsNil) + + username := "joe@example.com" + password := []byte("qweqweqwe") + _, _, err = CreateUserAndRole(s.a, username, []string{username}) + c.Assert(err, IsNil) + + token, err := s.a.CreateResetPasswordToken(context.TODO(), CreateResetPasswordTokenRequest{ + Name: username, + }) + + secrets, err := s.a.RotateResetPasswordTokenSecrets(context.TODO(), token.GetName()) + c.Assert(err, IsNil) + + otpToken, err := totp.GenerateCode(secrets.GetOTPKey(), s.bk.Clock().Now()) + c.Assert(err, IsNil) + + _, err = s.a.changePasswordWithToken(context.TODO(), ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + Password: password, + SecondFactorToken: otpToken, + }) + c.Assert(err, IsNil) + + err = s.a.CheckPasswordWOToken(username, password) + c.Assert(err, IsNil) +} + +func (s *PasswordSuite) TestChangePasswordWithTokenErrors(c *C) { + authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OTP, + }) + c.Assert(err, IsNil) + + username := "joe@example.com" + _, _, err = CreateUserAndRole(s.a, username, []string{username}) + c.Assert(err, IsNil) + + token, err := s.a.CreateResetPasswordToken(context.TODO(), CreateResetPasswordTokenRequest{ + Name: username, + }) + c.Assert(err, IsNil) + + validPassword := []byte("qweQWE1") + validTokenID := token.GetName() + + type testCase struct { + desc string + secondFactor string + req ChangePasswordWithTokenRequest + } + + testCases := []testCase{ + { + secondFactor: teleport.OFF, + desc: "invalid tokenID value", + req: ChangePasswordWithTokenRequest{ + TokenID: "what_token", + Password: validPassword, + }, + }, + { + secondFactor: teleport.OFF, + desc: "invalid password", + req: ChangePasswordWithTokenRequest{ + TokenID: validTokenID, + Password: []byte("short"), + }, + }, + { + secondFactor: teleport.OTP, + desc: "missing second factor", + req: ChangePasswordWithTokenRequest{ + TokenID: validTokenID, + Password: validPassword, + }, + }, + { + secondFactor: teleport.OTP, + desc: "invalid OTP value", + req: ChangePasswordWithTokenRequest{ + TokenID: validTokenID, + Password: validPassword, + SecondFactorToken: "invalid", + }, + }, + } + + for _, tc := range testCases { + // set new auth preference settings + authPreference.SetSecondFactor(tc.secondFactor) + err = s.a.SetAuthPreference(authPreference) + c.Assert(err, IsNil) + + _, err = s.a.changePasswordWithToken(context.TODO(), tc.req) + c.Assert(err, NotNil, Commentf("test case %q", tc.desc)) + } + + authPreference.SetSecondFactor(teleport.OFF) + err = s.a.SetAuthPreference(authPreference) + c.Assert(err, IsNil) + + _, err = s.a.changePasswordWithToken(context.TODO(), ChangePasswordWithTokenRequest{ + TokenID: validTokenID, + Password: validPassword, + }) + c.Assert(err, IsNil) + + // invite token cannot be reused + _, err = s.a.changePasswordWithToken(context.TODO(), ChangePasswordWithTokenRequest{ + TokenID: validTokenID, + Password: validPassword, + }) + c.Assert(err, NotNil) +} + func (s *PasswordSuite) shouldLockAfterFailedAttempts(c *C, req services.ChangePasswordReq) { loginAttempts, _ := s.a.GetUserLoginAttempts(req.User) c.Assert(len(loginAttempts), Equals, 0) diff --git a/lib/auth/proto/auth.pb.go b/lib/auth/proto/auth.pb.go index 3795b65df52b4..27ee7825618af 100644 --- a/lib/auth/proto/auth.pb.go +++ b/lib/auth/proto/auth.pb.go @@ -60,7 +60,7 @@ func (x Operation) String() string { return proto.EnumName(Operation_name, int32(x)) } func (Operation) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{0} + return fileDescriptor_auth_8605baa7098e7332, []int{0} } // Event returns cluster event @@ -93,7 +93,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{0} + return fileDescriptor_auth_8605baa7098e7332, []int{0} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -583,7 +583,7 @@ func (m *Watch) Reset() { *m = Watch{} } func (m *Watch) String() string { return proto.CompactTextString(m) } func (*Watch) ProtoMessage() {} func (*Watch) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{1} + return fileDescriptor_auth_8605baa7098e7332, []int{1} } func (m *Watch) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -641,7 +641,7 @@ func (m *WatchKind) Reset() { *m = WatchKind{} } func (m *WatchKind) String() string { return proto.CompactTextString(m) } func (*WatchKind) ProtoMessage() {} func (*WatchKind) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{2} + return fileDescriptor_auth_8605baa7098e7332, []int{2} } func (m *WatchKind) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -713,7 +713,7 @@ func (m *Certs) Reset() { *m = Certs{} } func (m *Certs) String() string { return proto.CompactTextString(m) } func (*Certs) ProtoMessage() {} func (*Certs) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{3} + return fileDescriptor_auth_8605baa7098e7332, []int{3} } func (m *Certs) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -766,7 +766,8 @@ type UserCertsRequest struct { // Expires is a desired time of the expiry of the certificate, could // be adjusted based on the permissions Expires time.Time `protobuf:"bytes,3,opt,name=Expires,stdtime" json:"expires,omitempty"` - // Format encodes the desired SSH Certificate format (either old ssh compatibility + // Format encodes the desired SSH Certificate format (either old ssh + // compatibility // format to remove some metadata causing trouble with old SSH servers) // or standard SSH cert format with custom extensions Format string `protobuf:"bytes,4,opt,name=Format,proto3" json:"format,omitempty"` @@ -786,7 +787,7 @@ func (m *UserCertsRequest) Reset() { *m = UserCertsRequest{} } func (m *UserCertsRequest) String() string { return proto.CompactTextString(m) } func (*UserCertsRequest) ProtoMessage() {} func (*UserCertsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{4} + return fileDescriptor_auth_8605baa7098e7332, []int{4} } func (m *UserCertsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -857,7 +858,7 @@ func (m *UserCertsRequest) GetAccessRequests() []string { return nil } -// GetUserRequest specifies paramters for the GetUser method. +// GetUserRequest specifies parameters for the GetUser method. type GetUserRequest struct { // Name is the name of the desired user. Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"name"` @@ -872,7 +873,7 @@ func (m *GetUserRequest) Reset() { *m = GetUserRequest{} } func (m *GetUserRequest) String() string { return proto.CompactTextString(m) } func (*GetUserRequest) ProtoMessage() {} func (*GetUserRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{5} + return fileDescriptor_auth_8605baa7098e7332, []int{5} } func (m *GetUserRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -928,7 +929,7 @@ func (m *GetUsersRequest) Reset() { *m = GetUsersRequest{} } func (m *GetUsersRequest) String() string { return proto.CompactTextString(m) } func (*GetUsersRequest) ProtoMessage() {} func (*GetUsersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{6} + return fileDescriptor_auth_8605baa7098e7332, []int{6} } func (m *GetUsersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -976,7 +977,7 @@ func (m *AccessRequests) Reset() { *m = AccessRequests{} } func (m *AccessRequests) String() string { return proto.CompactTextString(m) } func (*AccessRequests) ProtoMessage() {} func (*AccessRequests) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{7} + return fileDescriptor_auth_8605baa7098e7332, []int{7} } func (m *AccessRequests) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1026,7 +1027,7 @@ func (m *RequestStateSetter) Reset() { *m = RequestStateSetter{} } func (m *RequestStateSetter) String() string { return proto.CompactTextString(m) } func (*RequestStateSetter) ProtoMessage() {} func (*RequestStateSetter) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{8} + return fileDescriptor_auth_8605baa7098e7332, []int{8} } func (m *RequestStateSetter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1081,7 +1082,7 @@ func (m *RequestID) Reset() { *m = RequestID{} } func (m *RequestID) String() string { return proto.CompactTextString(m) } func (*RequestID) ProtoMessage() {} func (*RequestID) Descriptor() ([]byte, []int) { - return fileDescriptor_auth_3713a8b32977094f, []int{9} + return fileDescriptor_auth_8605baa7098e7332, []int{9} } func (m *RequestID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1117,6 +1118,172 @@ func (m *RequestID) GetID() string { return "" } +// RotateResetPasswordTokenSecretsRequest is a request to rotate token secrets. +type RotateResetPasswordTokenSecretsRequest struct { + TokenID string `protobuf:"bytes,1,opt,name=TokenID,proto3" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RotateResetPasswordTokenSecretsRequest) Reset() { + *m = RotateResetPasswordTokenSecretsRequest{} +} +func (m *RotateResetPasswordTokenSecretsRequest) String() string { return proto.CompactTextString(m) } +func (*RotateResetPasswordTokenSecretsRequest) ProtoMessage() {} +func (*RotateResetPasswordTokenSecretsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_8605baa7098e7332, []int{10} +} +func (m *RotateResetPasswordTokenSecretsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RotateResetPasswordTokenSecretsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RotateResetPasswordTokenSecretsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *RotateResetPasswordTokenSecretsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RotateResetPasswordTokenSecretsRequest.Merge(dst, src) +} +func (m *RotateResetPasswordTokenSecretsRequest) XXX_Size() int { + return m.Size() +} +func (m *RotateResetPasswordTokenSecretsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RotateResetPasswordTokenSecretsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RotateResetPasswordTokenSecretsRequest proto.InternalMessageInfo + +func (m *RotateResetPasswordTokenSecretsRequest) GetTokenID() string { + if m != nil { + return m.TokenID + } + return "" +} + +// GetResetPasswordTokenRequest is a request to get a reset password token. +type GetResetPasswordTokenRequest struct { + TokenID string `protobuf:"bytes,1,opt,name=TokenID,proto3" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetResetPasswordTokenRequest) Reset() { *m = GetResetPasswordTokenRequest{} } +func (m *GetResetPasswordTokenRequest) String() string { return proto.CompactTextString(m) } +func (*GetResetPasswordTokenRequest) ProtoMessage() {} +func (*GetResetPasswordTokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_8605baa7098e7332, []int{11} +} +func (m *GetResetPasswordTokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetResetPasswordTokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetResetPasswordTokenRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *GetResetPasswordTokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetResetPasswordTokenRequest.Merge(dst, src) +} +func (m *GetResetPasswordTokenRequest) XXX_Size() int { + return m.Size() +} +func (m *GetResetPasswordTokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetResetPasswordTokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetResetPasswordTokenRequest proto.InternalMessageInfo + +func (m *GetResetPasswordTokenRequest) GetTokenID() string { + if m != nil { + return m.TokenID + } + return "" +} + +// CreateResetPasswordTokenRequest is a request to create an instance of +// ResetPasswordToken +type CreateResetPasswordTokenRequest struct { + // Name is the user name. + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"name"` + // Type is a token type. + Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"type"` + // TTL specifies how long the generated token is valid for. + TTL Duration `protobuf:"varint,3,opt,name=TTL,proto3,casttype=Duration" json:"ttl"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateResetPasswordTokenRequest) Reset() { *m = CreateResetPasswordTokenRequest{} } +func (m *CreateResetPasswordTokenRequest) String() string { return proto.CompactTextString(m) } +func (*CreateResetPasswordTokenRequest) ProtoMessage() {} +func (*CreateResetPasswordTokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_8605baa7098e7332, []int{12} +} +func (m *CreateResetPasswordTokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateResetPasswordTokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateResetPasswordTokenRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *CreateResetPasswordTokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateResetPasswordTokenRequest.Merge(dst, src) +} +func (m *CreateResetPasswordTokenRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateResetPasswordTokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateResetPasswordTokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateResetPasswordTokenRequest proto.InternalMessageInfo + +func (m *CreateResetPasswordTokenRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *CreateResetPasswordTokenRequest) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *CreateResetPasswordTokenRequest) GetTTL() Duration { + if m != nil { + return m.TTL + } + return 0 +} + func init() { proto.RegisterType((*Event)(nil), "proto.Event") proto.RegisterType((*Watch)(nil), "proto.Watch") @@ -1129,6 +1296,9 @@ func init() { proto.RegisterType((*AccessRequests)(nil), "proto.AccessRequests") proto.RegisterType((*RequestStateSetter)(nil), "proto.RequestStateSetter") proto.RegisterType((*RequestID)(nil), "proto.RequestID") + proto.RegisterType((*RotateResetPasswordTokenSecretsRequest)(nil), "proto.RotateResetPasswordTokenSecretsRequest") + proto.RegisterType((*GetResetPasswordTokenRequest)(nil), "proto.GetResetPasswordTokenRequest") + proto.RegisterType((*CreateResetPasswordTokenRequest)(nil), "proto.CreateResetPasswordTokenRequest") proto.RegisterEnum("proto.Operation", Operation_name, Operation_value) } @@ -1149,7 +1319,8 @@ type AuthServiceClient interface { WatchEvents(ctx context.Context, in *Watch, opts ...grpc.CallOption) (AuthService_WatchEventsClient, error) // UpsertNode upserts node UpsertNode(ctx context.Context, in *services.ServerV2, opts ...grpc.CallOption) (*services.KeepAlive, error) - // GenerateUserCerts generates a set of user certificates for use by `tctl auth sign`. + // GenerateUserCerts generates a set of user certificates for use by `tctl + // auth sign`. GenerateUserCerts(ctx context.Context, in *UserCertsRequest, opts ...grpc.CallOption) (*Certs, error) // GetUser gets a user resource by name. GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*services.UserV2, error) @@ -1163,6 +1334,12 @@ type AuthServiceClient interface { DeleteAccessRequest(ctx context.Context, in *RequestID, opts ...grpc.CallOption) (*empty.Empty, error) // SetAccessRequestState sets the state of an access request. SetAccessRequestState(ctx context.Context, in *RequestStateSetter, opts ...grpc.CallOption) (*empty.Empty, error) + // RotateResetPasswordTokenSecrets rotates token secrets for a given tokenID. + RotateResetPasswordTokenSecrets(ctx context.Context, in *RotateResetPasswordTokenSecretsRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenSecretsV3, error) + // GetResetPasswordToken returns a token. + GetResetPasswordToken(ctx context.Context, in *GetResetPasswordTokenRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenV3, error) + // CreateResetPasswordToken creates ResetPasswordToken. + CreateResetPasswordToken(ctx context.Context, in *CreateResetPasswordTokenRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenV3, error) } type authServiceClient struct { @@ -1334,6 +1511,33 @@ func (c *authServiceClient) SetAccessRequestState(ctx context.Context, in *Reque return out, nil } +func (c *authServiceClient) RotateResetPasswordTokenSecrets(ctx context.Context, in *RotateResetPasswordTokenSecretsRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenSecretsV3, error) { + out := new(services.ResetPasswordTokenSecretsV3) + err := c.cc.Invoke(ctx, "/proto.AuthService/RotateResetPasswordTokenSecrets", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetResetPasswordToken(ctx context.Context, in *GetResetPasswordTokenRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenV3, error) { + out := new(services.ResetPasswordTokenV3) + err := c.cc.Invoke(ctx, "/proto.AuthService/GetResetPasswordToken", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) CreateResetPasswordToken(ctx context.Context, in *CreateResetPasswordTokenRequest, opts ...grpc.CallOption) (*services.ResetPasswordTokenV3, error) { + out := new(services.ResetPasswordTokenV3) + err := c.cc.Invoke(ctx, "/proto.AuthService/CreateResetPasswordToken", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for AuthService service type AuthServiceServer interface { @@ -1343,7 +1547,8 @@ type AuthServiceServer interface { WatchEvents(*Watch, AuthService_WatchEventsServer) error // UpsertNode upserts node UpsertNode(context.Context, *services.ServerV2) (*services.KeepAlive, error) - // GenerateUserCerts generates a set of user certificates for use by `tctl auth sign`. + // GenerateUserCerts generates a set of user certificates for use by `tctl + // auth sign`. GenerateUserCerts(context.Context, *UserCertsRequest) (*Certs, error) // GetUser gets a user resource by name. GetUser(context.Context, *GetUserRequest) (*services.UserV2, error) @@ -1357,6 +1562,12 @@ type AuthServiceServer interface { DeleteAccessRequest(context.Context, *RequestID) (*empty.Empty, error) // SetAccessRequestState sets the state of an access request. SetAccessRequestState(context.Context, *RequestStateSetter) (*empty.Empty, error) + // RotateResetPasswordTokenSecrets rotates token secrets for a given tokenID. + RotateResetPasswordTokenSecrets(context.Context, *RotateResetPasswordTokenSecretsRequest) (*services.ResetPasswordTokenSecretsV3, error) + // GetResetPasswordToken returns a token. + GetResetPasswordToken(context.Context, *GetResetPasswordTokenRequest) (*services.ResetPasswordTokenV3, error) + // CreateResetPasswordToken creates ResetPasswordToken. + CreateResetPasswordToken(context.Context, *CreateResetPasswordTokenRequest) (*services.ResetPasswordTokenV3, error) } func RegisterAuthServiceServer(s *grpc.Server, srv AuthServiceServer) { @@ -1557,6 +1768,60 @@ func _AuthService_SetAccessRequestState_Handler(srv interface{}, ctx context.Con return interceptor(ctx, in, info, handler) } +func _AuthService_RotateResetPasswordTokenSecrets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RotateResetPasswordTokenSecretsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).RotateResetPasswordTokenSecrets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/RotateResetPasswordTokenSecrets", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).RotateResetPasswordTokenSecrets(ctx, req.(*RotateResetPasswordTokenSecretsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetResetPasswordToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetResetPasswordTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetResetPasswordToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/GetResetPasswordToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetResetPasswordToken(ctx, req.(*GetResetPasswordTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_CreateResetPasswordToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateResetPasswordTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).CreateResetPasswordToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/CreateResetPasswordToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).CreateResetPasswordToken(ctx, req.(*CreateResetPasswordTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _AuthService_serviceDesc = grpc.ServiceDesc{ ServiceName: "proto.AuthService", HandlerType: (*AuthServiceServer)(nil), @@ -1589,6 +1854,18 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ MethodName: "SetAccessRequestState", Handler: _AuthService_SetAccessRequestState_Handler, }, + { + MethodName: "RotateResetPasswordTokenSecrets", + Handler: _AuthService_RotateResetPasswordTokenSecrets_Handler, + }, + { + MethodName: "GetResetPasswordToken", + Handler: _AuthService_GetResetPasswordToken_Handler, + }, + { + MethodName: "CreateResetPasswordToken", + Handler: _AuthService_CreateResetPasswordToken_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -2179,6 +2456,98 @@ func (m *RequestID) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *RotateResetPasswordTokenSecretsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RotateResetPasswordTokenSecretsRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.TokenID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintAuth(dAtA, i, uint64(len(m.TokenID))) + i += copy(dAtA[i:], m.TokenID) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *GetResetPasswordTokenRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetResetPasswordTokenRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.TokenID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintAuth(dAtA, i, uint64(len(m.TokenID))) + i += copy(dAtA[i:], m.TokenID) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *CreateResetPasswordTokenRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CreateResetPasswordTokenRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Name) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintAuth(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Type) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintAuth(dAtA, i, uint64(len(m.Type))) + i += copy(dAtA[i:], m.Type) + } + if m.TTL != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintAuth(dAtA, i, uint64(m.TTL)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func encodeVarintAuth(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -2485,21 +2854,67 @@ func (m *RequestID) Size() (n int) { return n } -func sovAuth(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } +func (m *RotateResetPasswordTokenSecretsRequest) Size() (n int) { + var l int + _ = l + l = len(m.TokenID) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) } return n } -func sozAuth(x uint64) (n int) { - return sovAuth(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Event) Unmarshal(dAtA []byte) error { - l := len(dAtA) + +func (m *GetResetPasswordTokenRequest) Size() (n int) { + var l int + _ = l + l = len(m.TokenID) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CreateResetPasswordTokenRequest) Size() (n int) { + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) + } + l = len(m.Type) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) + } + if m.TTL != 0 { + n += 1 + sovAuth(uint64(m.TTL)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovAuth(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozAuth(x uint64) (n int) { + return sovAuth(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Event) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -4086,6 +4501,294 @@ func (m *RequestID) Unmarshal(dAtA []byte) error { } return nil } +func (m *RotateResetPasswordTokenSecretsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RotateResetPasswordTokenSecretsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RotateResetPasswordTokenSecretsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuth(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuth + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetResetPasswordTokenRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetResetPasswordTokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetResetPasswordTokenRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuth(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuth + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CreateResetPasswordTokenRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CreateResetPasswordTokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateResetPasswordTokenRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TTL", wireType) + } + m.TTL = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TTL |= (Duration(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAuth(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuth + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipAuth(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 @@ -4191,95 +4894,105 @@ var ( ErrIntOverflowAuth = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("auth.proto", fileDescriptor_auth_3713a8b32977094f) } - -var fileDescriptor_auth_3713a8b32977094f = []byte{ - // 1386 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x56, 0x41, 0x6f, 0xdb, 0x46, - 0x16, 0x36, 0x65, 0x49, 0x96, 0x9e, 0x1c, 0x45, 0x19, 0x3b, 0x36, 0xa3, 0x38, 0xa6, 0xa1, 0x5c, - 0x8c, 0x6c, 0x20, 0x05, 0x0a, 0x76, 0x37, 0x6b, 0x2c, 0x10, 0x84, 0xb6, 0x12, 0x3b, 0x31, 0xb2, - 0x59, 0x4a, 0x51, 0x80, 0xf6, 0x20, 0xd0, 0xf4, 0x8b, 0x45, 0x98, 0x22, 0xd5, 0x99, 0x91, 0x5a, - 0x5f, 0xfb, 0x0b, 0x7a, 0xec, 0xbf, 0xe9, 0x35, 0xc7, 0xfe, 0x02, 0xb6, 0x4d, 0x6f, 0xfc, 0x0d, - 0x39, 0x14, 0x33, 0x24, 0x25, 0x0e, 0x1d, 0xf7, 0x44, 0xce, 0xf7, 0xde, 0xf7, 0xcd, 0xcc, 0xc7, - 0x37, 0x6f, 0x08, 0x60, 0xcf, 0xf8, 0xb8, 0x3d, 0xa5, 0x01, 0x0f, 0x48, 0x49, 0x3e, 0x9a, 0x9b, - 0x17, 0xc1, 0x45, 0x20, 0x5f, 0x3b, 0xe2, 0x2d, 0x0e, 0x36, 0xef, 0x5f, 0x04, 0xc1, 0x85, 0x87, - 0x1d, 0x39, 0x3a, 0x9b, 0x7d, 0xec, 0xe0, 0x64, 0xca, 0xaf, 0x92, 0xa0, 0x91, 0x0f, 0x72, 0x77, - 0x82, 0x8c, 0xdb, 0x93, 0x69, 0x92, 0x70, 0x70, 0xe1, 0xf2, 0xf1, 0xec, 0xac, 0xed, 0x04, 0x93, - 0xce, 0x05, 0xb5, 0xe7, 0x2e, 0xb7, 0xb9, 0x1b, 0xf8, 0xb6, 0xd7, 0xe1, 0xe8, 0xe1, 0x34, 0xa0, - 0xbc, 0xe3, 0xb9, 0x67, 0x1d, 0x86, 0x74, 0xee, 0x3a, 0xc8, 0x3a, 0xfc, 0x6a, 0x8a, 0x2c, 0xe6, - 0xb6, 0x7e, 0xa9, 0x42, 0xa9, 0x37, 0x47, 0x9f, 0x93, 0x67, 0x50, 0x1c, 0x5c, 0x4d, 0x51, 0xd7, - 0xf6, 0xb4, 0xfd, 0x7a, 0xb7, 0x11, 0xc7, 0xdb, 0xff, 0x9b, 0x22, 0x95, 0x6a, 0x26, 0x89, 0x42, - 0xa3, 0x2e, 0xa8, 0x8f, 0x83, 0x89, 0xcb, 0xe5, 0x02, 0x2d, 0xc9, 0x20, 0xdf, 0x40, 0xdd, 0x42, - 0x16, 0xcc, 0xa8, 0x83, 0xc7, 0x68, 0x9f, 0x23, 0xd5, 0x0b, 0x7b, 0xda, 0x7e, 0xad, 0xab, 0xb7, - 0xd3, 0x29, 0xdb, 0x6a, 0xdc, 0xdc, 0x8a, 0x42, 0x83, 0xd0, 0x04, 0x5b, 0xea, 0x1d, 0xaf, 0x58, - 0x39, 0x25, 0x32, 0x82, 0x5b, 0x87, 0x48, 0xf9, 0x8b, 0x19, 0x1f, 0x07, 0xd4, 0xe5, 0x57, 0xfa, - 0xaa, 0x94, 0xbe, 0xb7, 0x94, 0x56, 0xc2, 0xc3, 0xae, 0xb9, 0x13, 0x85, 0x86, 0xee, 0x20, 0xe5, - 0x23, 0x3b, 0x45, 0x95, 0x19, 0x54, 0x3d, 0xf2, 0x2d, 0xac, 0xf7, 0x85, 0x5f, 0xce, 0x20, 0xb8, - 0x44, 0x9f, 0xe9, 0xc5, 0xfc, 0xd2, 0xb3, 0xd1, 0x61, 0xd7, 0xbc, 0x1f, 0x85, 0xc6, 0x36, 0x93, - 0xd8, 0x88, 0x4b, 0x50, 0x51, 0x57, 0xc4, 0x88, 0x03, 0xf5, 0x77, 0x34, 0x98, 0xbb, 0xcc, 0x0d, - 0x7c, 0x09, 0xe9, 0x25, 0x29, 0xdf, 0x5c, 0xca, 0xab, 0xf1, 0x61, 0xd7, 0x7c, 0x10, 0x85, 0xc6, - 0xbd, 0x69, 0x8a, 0xc6, 0x73, 0xa8, 0x16, 0xa9, 0x14, 0xf2, 0x01, 0x6a, 0x87, 0xde, 0x8c, 0x71, - 0xa4, 0x6f, 0xed, 0x09, 0xea, 0x65, 0x39, 0xc3, 0x76, 0xc6, 0xa0, 0x65, 0x70, 0xd8, 0x35, 0x9b, - 0x51, 0x68, 0x6c, 0x39, 0x31, 0x34, 0xf2, 0xed, 0x89, 0x6a, 0x7f, 0x56, 0x49, 0x7a, 0x1f, 0x0f, - 0x0f, 0x03, 0xff, 0xa3, 0x7b, 0xa1, 0xaf, 0x5d, 0xf3, 0x3e, 0x1b, 0x1e, 0x3e, 0x4d, 0xbc, 0x4f, - 0xc4, 0x1d, 0x89, 0xe6, 0xbc, 0xcf, 0x12, 0xc8, 0x01, 0x14, 0xdf, 0x33, 0xa4, 0x7a, 0x45, 0xea, - 0x36, 0x96, 0xba, 0x02, 0x1d, 0x76, 0xe3, 0x92, 0x9b, 0x31, 0xa4, 0x8a, 0x88, 0xe4, 0x08, 0xae, - 0x15, 0x78, 0xa8, 0x57, 0xf3, 0x5c, 0x81, 0x0e, 0x9f, 0xc6, 0x5c, 0x1a, 0x78, 0xea, 0xfe, 0x24, - 0x87, 0x9c, 0x42, 0x55, 0x6c, 0x90, 0x4d, 0x6d, 0x07, 0x75, 0x90, 0x02, 0x1b, 0x4b, 0x81, 0x45, - 0xc8, 0xdc, 0x8e, 0x42, 0x63, 0xc3, 0x4f, 0x87, 0x8a, 0xd0, 0x52, 0x80, 0x98, 0x50, 0xee, 0x23, - 0x9d, 0x23, 0xd5, 0x6b, 0x52, 0x8a, 0x64, 0x6a, 0x47, 0xe2, 0xc3, 0xae, 0xb9, 0x19, 0x85, 0x46, - 0x83, 0xc9, 0x91, 0x22, 0x93, 0x30, 0x85, 0xd5, 0x16, 0xce, 0x91, 0x32, 0x1c, 0xcc, 0x7c, 0x1f, - 0x3d, 0x7d, 0x3d, 0x6f, 0xb5, 0x12, 0x4e, 0xcb, 0x9c, 0xc6, 0xe0, 0x88, 0x4b, 0x54, 0xb5, 0x5a, - 0x21, 0x90, 0x4b, 0x68, 0xc4, 0x6f, 0x87, 0x81, 0xef, 0xa3, 0x23, 0x4e, 0xb4, 0x7e, 0x4b, 0xce, - 0xb1, 0xb3, 0x9c, 0x23, 0x9f, 0x31, 0xec, 0x9a, 0x46, 0x14, 0x1a, 0xf7, 0x63, 0x79, 0xf1, 0x41, - 0x93, 0x80, 0x32, 0xd3, 0x35, 0x61, 0xb1, 0x9b, 0x17, 0x8e, 0x83, 0x8c, 0x59, 0xf8, 0xdd, 0x0c, - 0x19, 0xd7, 0xeb, 0xf9, 0xdd, 0x28, 0xe1, 0xb4, 0x70, 0x6c, 0x09, 0x8e, 0x68, 0x8c, 0xaa, 0xbb, - 0x51, 0x08, 0x26, 0x40, 0x25, 0xed, 0x13, 0xad, 0x63, 0x28, 0x7d, 0xb0, 0xb9, 0x33, 0x26, 0xcf, - 0xa1, 0xf4, 0xc6, 0xf5, 0xcf, 0x99, 0xae, 0xed, 0xad, 0xca, 0x92, 0x88, 0x3b, 0x98, 0x0c, 0x8a, - 0x80, 0xb9, 0xfd, 0x29, 0x34, 0x56, 0xa2, 0xd0, 0xb8, 0x7d, 0x29, 0xd2, 0x32, 0x6d, 0x2c, 0xe6, - 0xb5, 0x7e, 0x2c, 0x40, 0x75, 0x91, 0x4d, 0x76, 0xa0, 0x28, 0x9e, 0xb2, 0x1f, 0x56, 0xcd, 0x4a, - 0x14, 0x1a, 0x45, 0xc1, 0xb3, 0x24, 0x4a, 0xba, 0x50, 0x3b, 0x0d, 0xec, 0xf3, 0x3e, 0x3a, 0x14, - 0x39, 0x93, 0x0d, 0xaf, 0x62, 0x36, 0xa2, 0xd0, 0x58, 0xf7, 0x02, 0xfb, 0x7c, 0xc4, 0x62, 0xdc, - 0xca, 0x26, 0x09, 0x45, 0x79, 0x42, 0x57, 0x97, 0x8a, 0xa2, 0xb8, 0x2c, 0x89, 0x92, 0xd7, 0x50, - 0x7e, 0xe9, 0x7a, 0x1c, 0xa9, 0x5e, 0x94, 0xeb, 0xdf, 0xc9, 0xaf, 0xbf, 0x1d, 0x87, 0x7b, 0x3e, - 0xa7, 0x57, 0x71, 0x41, 0x7d, 0x94, 0x40, 0x66, 0x23, 0x89, 0x42, 0xf3, 0x3f, 0x50, 0xcb, 0x24, - 0x93, 0x06, 0xac, 0x5e, 0xe2, 0x55, 0xbc, 0x13, 0x4b, 0xbc, 0x92, 0x4d, 0x28, 0xcd, 0x6d, 0x6f, - 0x86, 0x72, 0xe1, 0x55, 0x2b, 0x1e, 0x1c, 0x14, 0x9e, 0x69, 0xad, 0xff, 0x43, 0x49, 0x34, 0x48, - 0x46, 0x1e, 0xc2, 0x6a, 0xbf, 0x7f, 0x2c, 0x49, 0xeb, 0xe6, 0x9d, 0x28, 0x34, 0x6e, 0x31, 0x36, - 0xce, 0xcc, 0x25, 0xa2, 0x22, 0x69, 0x70, 0xda, 0x97, 0x2a, 0x49, 0x12, 0xf7, 0xb2, 0xce, 0x8a, - 0x68, 0xeb, 0x4b, 0x01, 0x1a, 0xe2, 0xcc, 0x4a, 0xdd, 0xe4, 0x13, 0x92, 0xc7, 0x50, 0x7d, 0x37, - 0x3b, 0xf3, 0x5c, 0xe7, 0x4d, 0xb2, 0xb2, 0x75, 0xb3, 0x1e, 0x85, 0x06, 0x4c, 0x25, 0x38, 0xba, - 0xc4, 0x2b, 0x6b, 0x99, 0x40, 0xf6, 0xa1, 0x22, 0x14, 0x84, 0x5d, 0xf1, 0x92, 0xcd, 0xf5, 0x28, - 0x34, 0x2a, 0xb3, 0x04, 0xb3, 0x16, 0x51, 0xd2, 0x87, 0xb5, 0xde, 0x0f, 0x53, 0x97, 0x22, 0x4b, - 0xae, 0x8a, 0x66, 0x3b, 0xbe, 0x3f, 0xdb, 0xe9, 0xfd, 0xd9, 0x1e, 0xa4, 0xf7, 0xa7, 0xf9, 0x20, - 0xa9, 0x88, 0x3b, 0x18, 0x53, 0x96, 0x2b, 0xff, 0xe9, 0x37, 0x43, 0xb3, 0x52, 0x25, 0xf2, 0x18, - 0xca, 0x2f, 0x03, 0x3a, 0xb1, 0xb9, 0xbc, 0x1e, 0xaa, 0x89, 0xfb, 0x12, 0x51, 0xdc, 0x97, 0x08, - 0x79, 0x09, 0x75, 0x2b, 0x98, 0x71, 0x1c, 0x04, 0x49, 0xbb, 0x93, 0x5d, 0xbf, 0x6a, 0xee, 0x46, - 0xa1, 0xd1, 0xa4, 0x22, 0x32, 0xe2, 0xc1, 0x28, 0x69, 0x93, 0x19, 0x7e, 0x8e, 0x45, 0x7a, 0x50, - 0x57, 0xca, 0x9e, 0xe9, 0xe5, 0xbd, 0xd5, 0xfd, 0x6a, 0x7c, 0x43, 0xa8, 0x87, 0x25, 0xeb, 0x79, - 0x8e, 0xd4, 0xf2, 0xa0, 0xfe, 0x0a, 0xb9, 0x30, 0x28, 0xf5, 0x3e, 0x2d, 0x44, 0xed, 0xab, 0x85, - 0xf8, 0x5f, 0xa8, 0x7d, 0x70, 0xf9, 0x58, 0x2d, 0x6d, 0x79, 0x6d, 0x7c, 0xef, 0xf2, 0x71, 0x5a, - 0xda, 0x99, 0x09, 0xb3, 0xe9, 0xad, 0x1e, 0xdc, 0x4e, 0x66, 0x5b, 0x7c, 0xea, 0xae, 0x2a, 0xa8, - 0x2d, 0xcf, 0x4a, 0x56, 0x50, 0x95, 0x19, 0xe7, 0xf7, 0x4e, 0x86, 0xd7, 0xdc, 0x88, 0xcf, 0xf9, - 0xdf, 0x74, 0x95, 0x0d, 0x71, 0xd8, 0x73, 0x46, 0x5d, 0xb3, 0x07, 0x81, 0x24, 0xef, 0xe2, 0xea, - 0xc6, 0x3e, 0x72, 0xe1, 0xfd, 0x16, 0x14, 0x4e, 0x8e, 0x12, 0x83, 0xca, 0x51, 0x68, 0x14, 0xdc, - 0x73, 0xab, 0x70, 0x72, 0x44, 0xfe, 0x0d, 0x25, 0x99, 0x26, 0x6d, 0xa9, 0x77, 0xb7, 0xb2, 0x0d, - 0x7a, 0x29, 0x62, 0x56, 0xa3, 0xd0, 0x28, 0x89, 0xbf, 0x04, 0xb4, 0xe2, 0xfc, 0xd6, 0x43, 0xa8, - 0x26, 0x19, 0x27, 0x47, 0x37, 0xa9, 0x3f, 0x7a, 0x04, 0xd5, 0xc5, 0x0f, 0x17, 0xa9, 0x40, 0xf1, - 0xe4, 0xed, 0xc9, 0xa0, 0xb1, 0x42, 0xd6, 0x60, 0xf5, 0xdd, 0xfb, 0x41, 0x43, 0x23, 0x00, 0xe5, - 0xa3, 0xde, 0x69, 0x6f, 0xd0, 0x6b, 0x14, 0xba, 0x5f, 0x8a, 0x50, 0x13, 0xbf, 0x31, 0xfd, 0x78, - 0x01, 0xe4, 0x39, 0xd4, 0xfb, 0xe8, 0x9f, 0xbf, 0x41, 0x9c, 0xbe, 0xf0, 0xdc, 0x39, 0x32, 0x92, - 0xb9, 0xd3, 0x16, 0x68, 0x73, 0xeb, 0xda, 0x71, 0xe8, 0x89, 0x8f, 0xb8, 0xaf, 0x91, 0x7f, 0x40, - 0x4d, 0xf6, 0x1a, 0xf9, 0x3b, 0xc8, 0xc8, 0x7a, 0xb6, 0xff, 0x34, 0xd3, 0x91, 0x0c, 0x3e, 0xd1, - 0xc8, 0x3f, 0x01, 0xde, 0x4f, 0x19, 0x52, 0xfe, 0x36, 0x38, 0x47, 0xf2, 0x95, 0x2b, 0xaf, 0xf9, - 0xb5, 0xd9, 0xc9, 0x01, 0xdc, 0x79, 0x85, 0xbe, 0xd8, 0x21, 0x2e, 0x3a, 0x02, 0xd9, 0x4e, 0xb4, - 0xf3, 0x3d, 0x62, 0x31, 0x69, 0x9c, 0xd6, 0x85, 0xb5, 0xa4, 0xb2, 0xc8, 0xdd, 0x24, 0xa0, 0xd6, - 0x75, 0xf3, 0xda, 0x1f, 0x04, 0xf9, 0x17, 0x54, 0xd2, 0x6a, 0x24, 0x5b, 0x2a, 0x89, 0xdd, 0xc8, - 0x7a, 0xa2, 0x91, 0x13, 0xb1, 0x4e, 0x9e, 0xab, 0xc0, 0x07, 0x37, 0x54, 0x5a, 0xd2, 0x74, 0xd3, - 0x45, 0xe5, 0x58, 0xc7, 0xb0, 0x71, 0x48, 0xd1, 0xe6, 0xa8, 0xe0, 0xe4, 0xe6, 0xb2, 0xbd, 0xe9, - 0x13, 0x91, 0xe7, 0xb0, 0x71, 0x84, 0x1e, 0xe6, 0x95, 0xd2, 0x8b, 0x6e, 0x51, 0x5e, 0x37, 0x0a, - 0xbc, 0x86, 0xbb, 0xfd, 0xdc, 0xae, 0x64, 0x71, 0x92, 0x7b, 0xaa, 0x44, 0xe6, 0x20, 0xdc, 0xa4, - 0x65, 0x6e, 0x7e, 0xfa, 0x63, 0x57, 0xfb, 0xf4, 0x79, 0x57, 0xfb, 0xf5, 0xf3, 0xae, 0xf6, 0xfb, - 0xe7, 0x5d, 0xed, 0xe7, 0x3f, 0x77, 0x57, 0xce, 0xca, 0x32, 0xeb, 0xe9, 0x5f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xb0, 0x04, 0x19, 0xfa, 0x0c, 0x00, 0x00, +func init() { proto.RegisterFile("auth.proto", fileDescriptor_auth_8605baa7098e7332) } + +var fileDescriptor_auth_8605baa7098e7332 = []byte{ + // 1542 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x41, 0x6f, 0xdb, 0xc6, + 0x12, 0x36, 0x25, 0x4b, 0x96, 0x46, 0x8e, 0xa2, 0xac, 0x1d, 0x9b, 0x51, 0x1c, 0xd3, 0x90, 0x91, + 0xc0, 0xc8, 0xcb, 0x93, 0x02, 0x19, 0xef, 0xbd, 0x3c, 0xe3, 0x01, 0x41, 0x68, 0x2b, 0xb1, 0x13, + 0xbf, 0xd4, 0xa5, 0x14, 0x05, 0x68, 0x0b, 0x08, 0xb4, 0x34, 0xb1, 0x08, 0x53, 0xa2, 0xca, 0x5d, + 0x29, 0xf5, 0xb5, 0xe8, 0x0f, 0xe8, 0xb1, 0xff, 0xa4, 0xc7, 0x5e, 0x73, 0xec, 0x2f, 0x60, 0xdb, + 0xf4, 0xc6, 0x9f, 0x50, 0xf4, 0x50, 0xec, 0x92, 0x94, 0xb8, 0xb4, 0x95, 0xa4, 0x27, 0x71, 0xbf, + 0x99, 0xf9, 0x66, 0x77, 0x76, 0x66, 0x76, 0x04, 0x60, 0x8e, 0x59, 0xbf, 0x3a, 0x72, 0x1d, 0xe6, + 0x90, 0x8c, 0xf8, 0x29, 0xef, 0x9d, 0x59, 0xac, 0x3f, 0x3e, 0xad, 0x76, 0x9d, 0x41, 0xed, 0xcc, + 0x35, 0x27, 0x16, 0x33, 0x99, 0xe5, 0x0c, 0x4d, 0xbb, 0xc6, 0xd0, 0xc6, 0x91, 0xe3, 0xb2, 0x9a, + 0x6d, 0x9d, 0xd6, 0x28, 0xba, 0x13, 0xab, 0x8b, 0xb4, 0xc6, 0x2e, 0x46, 0x48, 0x03, 0x8a, 0xf2, + 0xea, 0x99, 0x73, 0xe6, 0x88, 0xcf, 0x1a, 0xff, 0x0a, 0xd1, 0xdb, 0x67, 0x8e, 0x73, 0x66, 0x63, + 0x4d, 0xac, 0x4e, 0xc7, 0x6f, 0x6a, 0x38, 0x18, 0xb1, 0x8b, 0x50, 0xa8, 0x25, 0x85, 0xcc, 0x1a, + 0x20, 0x65, 0xe6, 0x60, 0x14, 0x28, 0x54, 0x7e, 0xca, 0x43, 0xa6, 0x31, 0xc1, 0x21, 0x23, 0x8f, + 0x60, 0xb1, 0x75, 0x31, 0x42, 0x55, 0xd9, 0x52, 0x76, 0x8a, 0xf5, 0x52, 0x20, 0xaf, 0x7e, 0x36, + 0x42, 0x57, 0xec, 0x50, 0x27, 0xbe, 0xa7, 0x15, 0xf9, 0x76, 0x1e, 0x38, 0x03, 0x8b, 0x09, 0x27, + 0x86, 0xb0, 0x20, 0x5f, 0x40, 0xd1, 0x40, 0xea, 0x8c, 0xdd, 0x2e, 0x1e, 0xa2, 0xd9, 0x43, 0x57, + 0x4d, 0x6d, 0x29, 0x3b, 0x85, 0xba, 0x5a, 0x8d, 0x8e, 0x51, 0x95, 0xe5, 0xfa, 0x9a, 0xef, 0x69, + 0xc4, 0x0d, 0xb1, 0x19, 0xdf, 0xe1, 0x82, 0x91, 0x60, 0x22, 0x1d, 0xb8, 0xb6, 0x8f, 0x2e, 0x7b, + 0x32, 0x66, 0x7d, 0xc7, 0xb5, 0xd8, 0x85, 0x9a, 0x16, 0xd4, 0xb7, 0x66, 0xd4, 0x92, 0xb8, 0x5d, + 0xd7, 0x37, 0x7c, 0x4f, 0x53, 0xbb, 0xe8, 0xb2, 0x8e, 0x19, 0xa1, 0x92, 0x07, 0x99, 0x8f, 0x7c, + 0x09, 0xcb, 0x4d, 0x7e, 0x07, 0xdd, 0x96, 0x73, 0x8e, 0x43, 0xaa, 0x2e, 0x26, 0xb7, 0x1e, 0x97, + 0xb6, 0xeb, 0xfa, 0x6d, 0xdf, 0xd3, 0xd6, 0xa9, 0xc0, 0x3a, 0x4c, 0x80, 0x12, 0xbb, 0x44, 0x46, + 0xba, 0x50, 0x3c, 0x71, 0x9d, 0x89, 0x45, 0x2d, 0x67, 0x28, 0x20, 0x35, 0x23, 0xe8, 0xcb, 0x33, + 0x7a, 0x59, 0xde, 0xae, 0xeb, 0x77, 0x7c, 0x4f, 0xbb, 0x35, 0x8a, 0xd0, 0xc0, 0x87, 0x1c, 0x22, + 0xd9, 0x84, 0xbc, 0x86, 0xc2, 0xbe, 0x3d, 0xa6, 0x0c, 0xdd, 0x97, 0xe6, 0x00, 0xd5, 0xac, 0xf0, + 0xb0, 0x1e, 0x0b, 0xd0, 0x4c, 0xd8, 0xae, 0xeb, 0x65, 0xdf, 0xd3, 0xd6, 0xba, 0x01, 0xd4, 0x19, + 0x9a, 0x03, 0x39, 0xfc, 0x71, 0x26, 0x11, 0xfb, 0x60, 0xb9, 0xef, 0x0c, 0xdf, 0x58, 0x67, 0xea, + 0xd2, 0xa5, 0xd8, 0xc7, 0xc5, 0xed, 0xdd, 0x30, 0xf6, 0x21, 0x79, 0x57, 0xa0, 0x89, 0xd8, 0xc7, + 0x0d, 0xc8, 0x1e, 0x2c, 0xbe, 0xa2, 0xe8, 0xaa, 0x39, 0xc1, 0x5b, 0x9a, 0xf1, 0x72, 0xb4, 0x5d, + 0x0f, 0x52, 0x6e, 0x4c, 0xd1, 0x95, 0x48, 0x84, 0x0d, 0xb7, 0x35, 0x1c, 0x1b, 0xd5, 0x7c, 0xd2, + 0x96, 0xa3, 0xed, 0xdd, 0xc0, 0xd6, 0x75, 0x6c, 0xf9, 0x7c, 0xc2, 0x86, 0x1c, 0x43, 0x9e, 0x1f, + 0x90, 0x8e, 0xcc, 0x2e, 0xaa, 0x20, 0x08, 0x56, 0x66, 0x04, 0x53, 0x91, 0xbe, 0xee, 0x7b, 0xda, + 0xca, 0x30, 0x5a, 0x4a, 0x44, 0x33, 0x02, 0xa2, 0x43, 0xb6, 0x89, 0xee, 0x04, 0x5d, 0xb5, 0x20, + 0xa8, 0x48, 0x2c, 0x77, 0x04, 0xde, 0xae, 0xeb, 0xab, 0xbe, 0xa7, 0x95, 0xa8, 0x58, 0x49, 0x34, + 0xa1, 0x25, 0x0f, 0xb5, 0x81, 0x13, 0x74, 0x29, 0xb6, 0xc6, 0xc3, 0x21, 0xda, 0xea, 0x72, 0x32, + 0xd4, 0x92, 0x38, 0x4a, 0x73, 0x37, 0x00, 0x3b, 0x4c, 0xa0, 0x72, 0xa8, 0x25, 0x03, 0x72, 0x0e, + 0xa5, 0xe0, 0x6b, 0xdf, 0x19, 0x0e, 0xb1, 0xcb, 0x2b, 0x5a, 0xbd, 0x26, 0x7c, 0x6c, 0xcc, 0x7c, + 0x24, 0x35, 0xda, 0x75, 0x5d, 0xf3, 0x3d, 0xed, 0x76, 0x40, 0xcf, 0x2f, 0x34, 0x14, 0x48, 0x9e, + 0x2e, 0x11, 0xf3, 0xd3, 0x3c, 0xe9, 0x76, 0x91, 0x52, 0x03, 0xbf, 0x1e, 0x23, 0x65, 0x6a, 0x31, + 0x79, 0x1a, 0x49, 0x1c, 0x25, 0x8e, 0x29, 0xc0, 0x8e, 0x1b, 0xa0, 0xf2, 0x69, 0x24, 0x03, 0x1d, + 0x20, 0x17, 0xf5, 0x89, 0xca, 0x21, 0x64, 0x5e, 0x9b, 0xac, 0xdb, 0x27, 0x8f, 0x21, 0xf3, 0xc2, + 0x1a, 0xf6, 0xa8, 0xaa, 0x6c, 0xa5, 0x45, 0x4a, 0x04, 0x1d, 0x4c, 0x08, 0xb9, 0x40, 0x5f, 0x7f, + 0xe7, 0x69, 0x0b, 0xbe, 0xa7, 0x5d, 0x3f, 0xe7, 0x6a, 0xb1, 0x36, 0x16, 0xd8, 0x55, 0xbe, 0x4d, + 0x41, 0x7e, 0xaa, 0x4d, 0x36, 0x60, 0x91, 0xff, 0x8a, 0x7e, 0x98, 0xd7, 0x73, 0xbe, 0xa7, 0x2d, + 0x72, 0x3b, 0x43, 0xa0, 0xa4, 0x0e, 0x85, 0x63, 0xc7, 0xec, 0x35, 0xb1, 0xeb, 0x22, 0xa3, 0xa2, + 0xe1, 0xe5, 0xf4, 0x92, 0xef, 0x69, 0xcb, 0xb6, 0x63, 0xf6, 0x3a, 0x34, 0xc0, 0x8d, 0xb8, 0x12, + 0x67, 0x14, 0x15, 0x9a, 0x9e, 0x31, 0xf2, 0xe4, 0x32, 0x04, 0x4a, 0x9e, 0x43, 0xf6, 0xa9, 0x65, + 0x33, 0x74, 0xd5, 0x45, 0xb1, 0xff, 0x8d, 0xe4, 0xfe, 0xab, 0x81, 0xb8, 0x31, 0x64, 0xee, 0x45, + 0x90, 0x50, 0x6f, 0x04, 0x10, 0x3b, 0x48, 0xc8, 0x50, 0xfe, 0x2f, 0x14, 0x62, 0xca, 0xa4, 0x04, + 0xe9, 0x73, 0xbc, 0x08, 0x4e, 0x62, 0xf0, 0x4f, 0xb2, 0x0a, 0x99, 0x89, 0x69, 0x8f, 0x51, 0x6c, + 0x3c, 0x6f, 0x04, 0x8b, 0xbd, 0xd4, 0x23, 0xa5, 0xf2, 0x39, 0x64, 0x78, 0x83, 0xa4, 0x64, 0x1b, + 0xd2, 0xcd, 0xe6, 0xa1, 0x30, 0x5a, 0xd6, 0x6f, 0xf8, 0x9e, 0x76, 0x8d, 0xd2, 0x7e, 0xcc, 0x17, + 0x97, 0x72, 0xa5, 0xd6, 0x71, 0x53, 0xb0, 0x84, 0x4a, 0xcc, 0x8e, 0x47, 0x96, 0x4b, 0x2b, 0x7f, + 0xa6, 0xa0, 0xc4, 0x6b, 0x56, 0xf0, 0x86, 0x57, 0x48, 0x1e, 0x40, 0xfe, 0x64, 0x7c, 0x6a, 0x5b, + 0xdd, 0x17, 0xe1, 0xce, 0x96, 0xf5, 0xa2, 0xef, 0x69, 0x30, 0x12, 0x60, 0xe7, 0x1c, 0x2f, 0x8c, + 0x99, 0x02, 0xd9, 0x81, 0x1c, 0x67, 0xe0, 0xe1, 0x0a, 0xb6, 0xac, 0x2f, 0xfb, 0x9e, 0x96, 0x1b, + 0x87, 0x98, 0x31, 0x95, 0x92, 0x26, 0x2c, 0x35, 0xbe, 0x19, 0x59, 0x2e, 0xd2, 0xf0, 0xa9, 0x28, + 0x57, 0x83, 0x37, 0xb0, 0x1a, 0xbd, 0x81, 0xd5, 0x56, 0xf4, 0x06, 0xea, 0x77, 0xc2, 0x8c, 0xb8, + 0x81, 0x81, 0xc9, 0x6c, 0xe7, 0xdf, 0xff, 0xa2, 0x29, 0x46, 0xc4, 0x44, 0x1e, 0x40, 0xf6, 0xa9, + 0xe3, 0x0e, 0x4c, 0x26, 0x9e, 0x87, 0x7c, 0x18, 0x7d, 0x81, 0x48, 0xd1, 0x17, 0x08, 0x79, 0x0a, + 0x45, 0xc3, 0x19, 0x33, 0x6c, 0x39, 0x61, 0xbb, 0x13, 0x5d, 0x3f, 0xaf, 0x6f, 0xfa, 0x9e, 0x56, + 0x76, 0xb9, 0xa4, 0xc3, 0x9c, 0x4e, 0xd8, 0x26, 0x63, 0xf6, 0x09, 0x2b, 0xd2, 0x80, 0xa2, 0x94, + 0xf6, 0x54, 0xcd, 0x6e, 0xa5, 0x77, 0xf2, 0xc1, 0x0b, 0x21, 0x17, 0x4b, 0x3c, 0xe6, 0x09, 0xa3, + 0x8a, 0x0d, 0xc5, 0x67, 0xc8, 0x78, 0x80, 0xa2, 0xd8, 0x47, 0x89, 0xa8, 0x5c, 0x99, 0x88, 0xff, + 0x83, 0xc2, 0x6b, 0x8b, 0xf5, 0xe5, 0xd4, 0x16, 0xcf, 0xc6, 0x5b, 0x8b, 0xf5, 0xa3, 0xd4, 0x8e, + 0x39, 0x8c, 0xab, 0x57, 0x1a, 0x70, 0x3d, 0xf4, 0x36, 0xbd, 0xea, 0xba, 0x4c, 0xa8, 0xcc, 0x6a, + 0x25, 0x4e, 0x28, 0xd3, 0xf4, 0x93, 0x67, 0x27, 0xed, 0x4b, 0xd1, 0x08, 0xea, 0xfc, 0x03, 0x5d, + 0x65, 0x85, 0x17, 0x7b, 0x22, 0x50, 0x97, 0xc2, 0x83, 0x40, 0xc2, 0x6f, 0xfe, 0x74, 0x63, 0x13, + 0x19, 0x8f, 0xfd, 0x1a, 0xa4, 0x8e, 0x0e, 0xc2, 0x00, 0x65, 0x7d, 0x4f, 0x4b, 0x59, 0x3d, 0x23, + 0x75, 0x74, 0x40, 0xfe, 0x03, 0x19, 0xa1, 0x26, 0xc2, 0x52, 0xac, 0xaf, 0xc5, 0x1b, 0xf4, 0x8c, + 0x44, 0xcf, 0xfb, 0x9e, 0x96, 0xe1, 0x53, 0x02, 0x1a, 0x81, 0x7e, 0x65, 0x1b, 0xf2, 0xa1, 0xc6, + 0xd1, 0xc1, 0x3c, 0xf6, 0xca, 0xff, 0xe1, 0x9e, 0xe1, 0x08, 0x2b, 0xa4, 0xc8, 0x4e, 0x4c, 0x4a, + 0xdf, 0x3a, 0x6e, 0x4f, 0x3c, 0xf3, 0x61, 0x60, 0xa2, 0x98, 0x6e, 0xc3, 0x92, 0x80, 0xa7, 0x34, + 0xc2, 0xa3, 0x18, 0x16, 0x8c, 0x48, 0x52, 0xd9, 0x87, 0x8d, 0x67, 0xc8, 0x2e, 0x73, 0xfd, 0x2d, + 0x92, 0xef, 0x14, 0xd0, 0xf6, 0x5d, 0xbc, 0x72, 0x53, 0x9f, 0x96, 0x50, 0x1b, 0xe1, 0x64, 0x99, + 0x9a, 0x49, 0xf9, 0x1c, 0x19, 0x4e, 0x8f, 0x77, 0x21, 0xdd, 0x6a, 0x1d, 0x8b, 0x62, 0x4d, 0x8b, + 0x1b, 0x4b, 0x33, 0x66, 0xff, 0xe1, 0x69, 0xb9, 0x83, 0x71, 0x30, 0x79, 0x1a, 0x5c, 0x7e, 0xff, + 0x3e, 0xe4, 0xa7, 0xb3, 0x28, 0xc9, 0xc1, 0xe2, 0xd1, 0xcb, 0xa3, 0x56, 0x69, 0x81, 0x2c, 0x41, + 0xfa, 0xe4, 0x55, 0xab, 0xa4, 0x10, 0x80, 0xec, 0x41, 0xe3, 0xb8, 0xd1, 0x6a, 0x94, 0x52, 0xf5, + 0x1f, 0x97, 0xa0, 0xc0, 0x27, 0xbc, 0x66, 0x70, 0x37, 0xe4, 0x31, 0x14, 0x9b, 0x38, 0xec, 0xbd, + 0x40, 0x1c, 0x3d, 0xb1, 0xad, 0x09, 0x52, 0x12, 0x7b, 0xee, 0xa7, 0x68, 0x79, 0xed, 0x52, 0xa7, + 0x68, 0xf0, 0xfc, 0xde, 0x51, 0xc8, 0x3f, 0xa0, 0x20, 0xda, 0xb0, 0x98, 0x94, 0x29, 0x59, 0x8e, + 0xb7, 0xe6, 0x72, 0xb4, 0x12, 0xc2, 0x87, 0x0a, 0xf9, 0x17, 0xc0, 0xab, 0x11, 0x45, 0x97, 0xbd, + 0x74, 0x7a, 0x48, 0xae, 0x98, 0x06, 0xca, 0x57, 0x79, 0x27, 0x7b, 0x70, 0xe3, 0x19, 0x0e, 0xf9, + 0x09, 0x71, 0xda, 0x2c, 0xc9, 0x7a, 0xc8, 0x9d, 0x6c, 0x9f, 0x53, 0xa7, 0x81, 0x5a, 0x1d, 0x96, + 0xc2, 0xa2, 0x23, 0x37, 0x43, 0x81, 0x5c, 0xf2, 0xe5, 0x4b, 0xc3, 0x15, 0xf9, 0x37, 0xe4, 0xa2, + 0x42, 0x25, 0x6b, 0xb2, 0x11, 0x9d, 0x6b, 0xf5, 0x50, 0x21, 0x47, 0x7c, 0x9f, 0x2c, 0x51, 0x9c, + 0x77, 0xe6, 0x14, 0x61, 0xf8, 0x1e, 0x45, 0x9b, 0x4a, 0x58, 0x1d, 0xc2, 0x4a, 0x90, 0x59, 0x12, + 0x4e, 0xe6, 0x57, 0xf4, 0xbc, 0x2b, 0x22, 0x8f, 0x61, 0xe5, 0x00, 0x6d, 0x4c, 0x32, 0x45, 0x33, + 0xc0, 0xb4, 0xf2, 0xe6, 0x12, 0x3c, 0x87, 0x9b, 0xcd, 0xc4, 0xa9, 0x44, 0xdd, 0x92, 0x5b, 0x32, + 0x45, 0xac, 0x47, 0xcc, 0xe5, 0x7a, 0x0b, 0xda, 0x47, 0xaa, 0x98, 0xfc, 0x33, 0x62, 0xfd, 0xa4, + 0x6a, 0x2f, 0xdf, 0x95, 0xfe, 0x49, 0x5d, 0xad, 0xdb, 0xde, 0x25, 0x5f, 0xc1, 0xcd, 0x2b, 0xeb, + 0x9d, 0x6c, 0xcf, 0xee, 0x77, 0x6e, 0x11, 0x97, 0x37, 0x3f, 0xe4, 0xa4, 0xbd, 0x4b, 0x4e, 0x41, + 0x9d, 0xd7, 0x07, 0xc8, 0xbd, 0x28, 0x1d, 0x3f, 0xdc, 0x28, 0x3e, 0xe6, 0x43, 0x5f, 0x7d, 0xf7, + 0xdb, 0xa6, 0xf2, 0xee, 0xfd, 0xa6, 0xf2, 0xf3, 0xfb, 0x4d, 0xe5, 0xd7, 0xf7, 0x9b, 0xca, 0x0f, + 0xbf, 0x6f, 0x2e, 0x9c, 0x66, 0x05, 0xf9, 0xee, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x32, 0x0f, + 0xa0, 0x0c, 0x50, 0x0f, 0x00, 0x00, } diff --git a/lib/auth/proto/auth.proto b/lib/auth/proto/auth.proto index 61e27cc846670..aba7dff6d9f5e 100644 --- a/lib/auth/proto/auth.proto +++ b/lib/auth/proto/auth.proto @@ -1,10 +1,11 @@ syntax = "proto3"; package proto; +import "github.com/gravitational/teleport/lib/services/types.proto"; + import "gogoproto/gogo.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; -import "github.com/gravitational/teleport/lib/services/types.proto"; option (gogoproto.marshaler_all) = true; option (gogoproto.unmarshaler_all) = true; @@ -14,9 +15,9 @@ option (gogoproto.goproto_getters_all) = true; enum Operation { // INIT is sent as a first sentinel event // on the watch channel - INIT = 0; + INIT = 0; // PUT identifies created or updated object - PUT = 1; + PUT = 1; // DELETE identifies deleted object DELETE = 2; } @@ -24,121 +25,152 @@ enum Operation { // Event returns cluster event message Event { // Operation identifies operation - Operation Type = 1 [(gogoproto.jsontag) = "type,omitempty"]; + Operation Type = 1 [ (gogoproto.jsontag) = "type,omitempty" ]; // Resource contains the updated resource oneof Resource { // ResourceHeader is specified in delete events, // the full object is not available, so resource // header is used to provide information about object type - services.ResourceHeader ResourceHeader = 2 [(gogoproto.jsontag) = "resource,omitempty"]; + services.ResourceHeader ResourceHeader = 2 [ (gogoproto.jsontag) = "resource,omitempty" ]; // CertAuthority is filled in certificate-authority related events - services.CertAuthorityV2 CertAuthority = 3 [(gogoproto.jsontag) = "cert_authority,omitempty"]; + services.CertAuthorityV2 CertAuthority = 3 + [ (gogoproto.jsontag) = "cert_authority,omitempty" ]; // StaticTokens is filled in static-tokens related events - services.StaticTokensV2 StaticTokens = 4 [(gogoproto.jsontag) = "static_tokens,omitempty"]; + services.StaticTokensV2 StaticTokens = 4 + [ (gogoproto.jsontag) = "static_tokens,omitempty" ]; // ProvisionToken is filled in provision-token related events - services.ProvisionTokenV2 ProvisionToken = 5 [(gogoproto.jsontag) = "provision_token,omitempty"]; + services.ProvisionTokenV2 ProvisionToken = 5 + [ (gogoproto.jsontag) = "provision_token,omitempty" ]; // ClusterNameV2 is a cluster name resource - services.ClusterNameV2 ClusterName = 6 [(gogoproto.jsontag) = "cluster_name,omitempty"]; + services.ClusterNameV2 ClusterName = 6 [ (gogoproto.jsontag) = "cluster_name,omitempty" ]; // ClusterConfig is a cluster configuration resource - services.ClusterConfigV3 ClusterConfig = 7 [(gogoproto.jsontag) = "cluster_config,omitempty"]; + services.ClusterConfigV3 ClusterConfig = 7 + [ (gogoproto.jsontag) = "cluster_config,omitempty" ]; // User is a user resource - services.UserV2 User = 8 [(gogoproto.jsontag) = "user,omitempty"]; + services.UserV2 User = 8 [ (gogoproto.jsontag) = "user,omitempty" ]; // Role is a role resource - services.RoleV3 Role = 9 [(gogoproto.jsontag) = "role,omitempty"]; + services.RoleV3 Role = 9 [ (gogoproto.jsontag) = "role,omitempty" ]; // Namespace is a namespace resource - services.Namespace Namespace = 10 [(gogoproto.jsontag) = "namespace,omitempty"]; + services.Namespace Namespace = 10 [ (gogoproto.jsontag) = "namespace,omitempty" ]; // Server is a node or proxy resource - services.ServerV2 Server = 11 [(gogoproto.jsontag) = "server,omitempty"]; + services.ServerV2 Server = 11 [ (gogoproto.jsontag) = "server,omitempty" ]; // ReverseTunnel is a resource with reverse tunnel - services.ReverseTunnelV2 ReverseTunnel = 12 [(gogoproto.jsontag) = "reverse_tunnel,omitempty"]; + services.ReverseTunnelV2 ReverseTunnel = 12 + [ (gogoproto.jsontag) = "reverse_tunnel,omitempty" ]; // TunnelConnection is a resource for tunnel connnections - services.TunnelConnectionV2 TunnelConnection = 13 [(gogoproto.jsontag) = "tunnel_connection,omitempty"]; + services.TunnelConnectionV2 TunnelConnection = 13 + [ (gogoproto.jsontag) = "tunnel_connection,omitempty" ]; // AccessRequest is a resource for access requests - services.AccessRequestV3 AccessRequest = 14 [(gogoproto.jsontag) = "access_request,omitempty"]; + services.AccessRequestV3 AccessRequest = 14 + [ (gogoproto.jsontag) = "access_request,omitempty" ]; } } // Watch specifies watch parameters message Watch { // Kinds specifies object kinds to watch - repeated WatchKind Kinds = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "kinds,omitempty"]; + repeated WatchKind Kinds = 1 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "kinds,omitempty" ]; } // WatchKind specifies resource kind to watch message WatchKind { // Kind is a resource kind to watch - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // LoadSecrets specifies whether to load secrets - bool LoadSecrets = 2 [(gogoproto.jsontag) = "load_secrets"]; + bool LoadSecrets = 2 [ (gogoproto.jsontag) = "load_secrets" ]; // Name is an optional specific resource type to watch, // if specified only the events with a specific resource // name will be sent - string Name = 3 [(gogoproto.jsontag) = "name"]; + string Name = 3 [ (gogoproto.jsontag) = "name" ]; // Filter is an optional mapping of custom filter parameters. // Valid values vary by resource kind. - map Filter = 4 [(gogoproto.jsontag) = "filter,omitempty"]; + map Filter = 4 [ (gogoproto.jsontag) = "filter,omitempty" ]; } // Set of certificates corresponding to a single public key. message Certs { // SSH X509 cert (PEM-encoded). - bytes SSH = 1 [(gogoproto.jsontag) = "ssh,omitempty"]; + bytes SSH = 1 [ (gogoproto.jsontag) = "ssh,omitempty" ]; // TLS X509 cert (PEM-encoded). - bytes TLS = 2 [(gogoproto.jsontag) = "tls,omitempty"]; + bytes TLS = 2 [ (gogoproto.jsontag) = "tls,omitempty" ]; } // UserCertRequest specifies certificate-generation parameters // for a user. message UserCertsRequest { // PublicKey is a public key to be signed. - bytes PublicKey = 1 [(gogoproto.jsontag) = "public_key"]; + bytes PublicKey = 1 [ (gogoproto.jsontag) = "public_key" ]; // Username of key owner. - string Username = 2 [(gogoproto.jsontag) = "username"]; - // Expires is a desired time of the expiry of the certificate, could + string Username = 2 [ (gogoproto.jsontag) = "username" ]; + // Expires is a desired time of the expiry of the certificate, could // be adjusted based on the permissions - google.protobuf.Timestamp Expires = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "expires,omitempty"]; - // Format encodes the desired SSH Certificate format (either old ssh compatibility + google.protobuf.Timestamp Expires = 3 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expires,omitempty" + ]; + // Format encodes the desired SSH Certificate format (either old ssh + // compatibility // format to remove some metadata causing trouble with old SSH servers) // or standard SSH cert format with custom extensions - string Format = 4 [(gogoproto.jsontag) = "format,omitempty"]; + string Format = 4 [ (gogoproto.jsontag) = "format,omitempty" ]; // RouteToCluster is an optional cluster name to add to the certificate, // so that requests originating with this certificate will be redirected // to this cluster - string RouteToCluster = 5 [(gogoproto.jsontag) = "route_to_cluster,omitempty"]; + string RouteToCluster = 5 [ (gogoproto.jsontag) = "route_to_cluster,omitempty" ]; // AccessRequests is an optional list of request IDs indicating requests whose // escalated privileges should be added to the certificate. - repeated string AccessRequests = 6 [(gogoproto.jsontag) = "access_requests,omitempty"]; + repeated string AccessRequests = 6 [ (gogoproto.jsontag) = "access_requests,omitempty" ]; } -// GetUserRequest specifies paramters for the GetUser method. +// GetUserRequest specifies parameters for the GetUser method. message GetUserRequest { // Name is the name of the desired user. - string Name = 1 [(gogoproto.jsontag) = "name"]; + string Name = 1 [ (gogoproto.jsontag) = "name" ]; // WithSecrets specifies whether to load associated secrets. - bool WithSecrets = 2 [(gogoproto.jsontag) = "with_secrets,omitempty"]; + bool WithSecrets = 2 [ (gogoproto.jsontag) = "with_secrets,omitempty" ]; } // GetUsersRequest specifies parameters for the GetUsers method. message GetUsersRequest { // WithSecrets specifies whether to load associated secrets. - bool WithSecrets = 1 [(gogoproto.jsontag) = "with_secrets"]; + bool WithSecrets = 1 [ (gogoproto.jsontag) = "with_secrets" ]; } // AccessRequests is a collection of AccessRequest values. message AccessRequests { - repeated services.AccessRequestV3 AccessRequests = 1 [(gogoproto.jsontag) = "access_requests"]; + repeated services.AccessRequestV3 AccessRequests = 1 + [ (gogoproto.jsontag) = "access_requests" ]; } // RequestStateSetter encodes the paramters necessary to update the // state of a privilege escalation request. message RequestStateSetter { - string ID = 1 [(gogoproto.jsontag) = "id"]; - services.RequestState State = 2 [(gogoproto.jsontag) = "state"]; + string ID = 1 [ (gogoproto.jsontag) = "id" ]; + services.RequestState State = 2 [ (gogoproto.jsontag) = "state" ]; } // RequestID is the unique identifier of an access request. -message RequestID { - string ID = 1 [(gogoproto.jsontag) = "id"]; +message RequestID { string ID = 1 [ (gogoproto.jsontag) = "id" ]; } + +// RotateResetPasswordTokenSecretsRequest is a request to rotate token secrets. +message RotateResetPasswordTokenSecretsRequest { + string TokenID = 1 [ (gogoproto.jsontag) = "token" ]; +} + +// GetResetPasswordTokenRequest is a request to get a reset password token. +message GetResetPasswordTokenRequest { string TokenID = 1 [ (gogoproto.jsontag) = "token" ]; } + +// CreateResetPasswordTokenRequest is a request to create an instance of +// ResetPasswordToken +message CreateResetPasswordTokenRequest { + // Name is the user name. + string Name = 1 [ (gogoproto.jsontag) = "name" ]; + // Type is a token type. + string Type = 2 [ (gogoproto.jsontag) = "type" ]; + // TTL specifies how long the generated token is valid for. + int64 TTL = 3 [ (gogoproto.jsontag) = "ttl", (gogoproto.casttype) = "Duration" ]; } // AuthService is authentication/authorization service implementation @@ -149,7 +181,8 @@ service AuthService { rpc WatchEvents(Watch) returns (stream Event); // UpsertNode upserts node rpc UpsertNode(services.ServerV2) returns (services.KeepAlive); - // GenerateUserCerts generates a set of user certificates for use by `tctl auth sign`. + // GenerateUserCerts generates a set of user certificates for use by `tctl + // auth sign`. rpc GenerateUserCerts(UserCertsRequest) returns (Certs); // GetUser gets a user resource by name. rpc GetUser(GetUserRequest) returns (services.UserV2); @@ -163,4 +196,12 @@ service AuthService { rpc DeleteAccessRequest(RequestID) returns (google.protobuf.Empty); // SetAccessRequestState sets the state of an access request. rpc SetAccessRequestState(RequestStateSetter) returns (google.protobuf.Empty); -} + // RotateResetPasswordTokenSecrets rotates token secrets for a given tokenID. + rpc RotateResetPasswordTokenSecrets(RotateResetPasswordTokenSecretsRequest) + returns (services.ResetPasswordTokenSecretsV3); + // GetResetPasswordToken returns a token. + rpc GetResetPasswordToken(GetResetPasswordTokenRequest) returns (services.ResetPasswordTokenV3); + // CreateResetPasswordToken creates ResetPasswordToken. + rpc CreateResetPasswordToken(CreateResetPasswordTokenRequest) + returns (services.ResetPasswordTokenV3); +} \ No newline at end of file diff --git a/lib/auth/proto/proto.go b/lib/auth/proto/proto.go new file mode 100644 index 0000000000000..39b9ed89ede9b --- /dev/null +++ b/lib/auth/proto/proto.go @@ -0,0 +1,16 @@ +package proto + +import "time" + +// Duration is a wrapper around duration to set up custom marshal/unmarshal +type Duration time.Duration + +// Get returns time.Duration value +func (d Duration) Get() time.Duration { + return time.Duration(d) +} + +// Set sets time.Duration value +func (d *Duration) Set(value time.Duration) { + *d = Duration(value) +} diff --git a/lib/auth/resetpasswordtoken.go b/lib/auth/resetpasswordtoken.go new file mode 100644 index 0000000000000..e182142fe920f --- /dev/null +++ b/lib/auth/resetpasswordtoken.go @@ -0,0 +1,256 @@ +/* +Copyright 2017-2020 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 auth + +import ( + "bytes" + "context" + "fmt" + "image/png" + "net/url" + "time" + + "github.com/gravitational/teleport/lib/defaults" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/utils" + + "github.com/gravitational/trace" + + "github.com/pquerna/otp/totp" +) + +const ( + // ResetPasswordTokenTypeInvite indicates invite UI flow + ResetPasswordTokenTypeInvite = "invite" + // ResetPasswordTokenTypePassword indicates set new password UI flow + ResetPasswordTokenTypePassword = "password" +) + +// CreateResetPasswordTokenRequest is a request to create a new reset password token +type CreateResetPasswordTokenRequest struct { + // Name is the user name to reset. + Name string `json:"name"` + // TTL specifies how long the generated reset token is valid for. + TTL time.Duration `json:"ttl"` + // Type is a token type. + Type string `json:"type"` +} + +// CheckAndSetDefaults checks and sets the defaults +func (r *CreateResetPasswordTokenRequest) CheckAndSetDefaults() error { + if r.Name == "" { + return trace.BadParameter("user name can't be empty") + } + if r.TTL < 0 { + return trace.BadParameter("TTL can't be negative") + } + + if r.Type == "" { + r.Type = ResetPasswordTokenTypePassword + } + + // We use the same mechanism to handle invites and password resets + // as both allow setting up a new password based on auth preferences. + // The only difference is default TTL values and URLs to web UI. + switch r.Type { + case ResetPasswordTokenTypeInvite: + if r.TTL == 0 { + r.TTL = defaults.SignupTokenTTL + } + + if r.TTL > defaults.MaxSignupTokenTTL { + return trace.BadParameter( + "failed to create user invite token: maximum token TTL is %v hours", + defaults.MaxSignupTokenTTL) + } + case ResetPasswordTokenTypePassword: + if r.TTL == 0 { + r.TTL = defaults.ChangePasswordTokenTTL + } + if r.TTL > defaults.MaxChangePasswordTokenTTL { + return trace.BadParameter( + "failed to create reset password token: maximum token TTL is %v hours", + defaults.MaxChangePasswordTokenTTL) + } + default: + return trace.BadParameter("unknown reset password token request type(%v)", r.Type) + } + + return nil +} + +// CreateResetPasswordToken creates a reset password token +func (s *AuthServer) CreateResetPasswordToken(ctx context.Context, req CreateResetPasswordTokenRequest) (services.ResetPasswordToken, error) { + err := req.CheckAndSetDefaults() + if err != nil { + return nil, trace.Wrap(err) + } + + _, err = s.GetUser(req.Name, false) + if err != nil { + return nil, trace.Wrap(err) + } + + _, err = s.ResetPassword(req.Name) + if err != nil { + return nil, trace.Wrap(err) + } + + token, err := s.newResetPasswordToken(req) + if err != nil { + return nil, trace.Wrap(err) + } + + // remove any other existing tokens for this user + err = s.deleteResetPasswordTokens(ctx, req.Name) + if err != nil { + return nil, trace.Wrap(err) + } + + _, err = s.Identity.CreateResetPasswordToken(ctx, token) + if err != nil { + return nil, trace.Wrap(err) + } + + return s.GetResetPasswordToken(ctx, token.GetName()) +} + +// RotateResetPasswordTokenSecrets rotates secrets for a given tokenID. +// It gets called every time a user fetches 2nd-factor secrets during registration attempt. +// This ensures that an attacker that gains the ResetPasswordToken link can not view it, +// extract the OTP key from the QR code, then allow the user to signup with +// the same OTP token. +func (s *AuthServer) RotateResetPasswordTokenSecrets(ctx context.Context, tokenID string) (services.ResetPasswordTokenSecrets, error) { + token, err := s.GetResetPasswordToken(ctx, tokenID) + if err != nil { + return nil, trace.Wrap(err) + } + + key, qr, err := newTOTPKeys("Teleport", token.GetUser()+"@"+s.AuthServiceName) + if err != nil { + return nil, trace.Wrap(err) + } + + secrets, err := services.NewResetPasswordTokenSecrets(tokenID) + if err != nil { + return nil, trace.Wrap(err) + } + + secrets.Spec.OTPKey = key + secrets.Spec.QRCode = string(qr) + err = s.UpsertResetPasswordTokenSecrets(ctx, &secrets) + if err != nil { + return nil, trace.Wrap(err) + } + + return &secrets, nil +} + +func (s *AuthServer) newResetPasswordToken(req CreateResetPasswordTokenRequest) (services.ResetPasswordToken, error) { + tokenID, err := utils.CryptoRandomHex(TokenLenBytes) + if err != nil { + return nil, trace.Wrap(err) + } + + url, err := formatResetPasswordTokenURL(s.publicURL(), tokenID, req.Type) + if err != nil { + return nil, trace.Wrap(err) + } + + token := services.NewResetPasswordToken(tokenID) + token.Metadata.SetExpiry(s.clock.Now().UTC().Add(req.TTL)) + token.Spec.User = req.Name + token.Spec.Created = s.clock.Now().UTC() + token.Spec.URL = url + return &token, nil +} + +func (s *AuthServer) publicURL() string { + proxyHost := ":3080" + proxies, err := s.GetProxies() + if err != nil { + log.Errorf("Unable to retrieve proxy list: %v", err) + } + + if len(proxies) > 0 { + proxyHost = proxies[0].GetPublicAddr() + if proxyHost == "" { + proxyHost = fmt.Sprintf("%v:%v", proxies[0].GetHostname(), defaults.HTTPListenPort) + log.Debugf("public_address not set for proxy, returning proxyHost: %q", proxyHost) + } + } + + return fmt.Sprintf("https://" + proxyHost) +} + +func formatResetPasswordTokenURL(advertiseURL string, tokenID string, reqType string) (string, error) { + u, err := url.Parse(advertiseURL) + if err != nil { + return "", trace.Wrap(err) + } + + u.RawQuery = "" + // We have 2 differen UI flows to process password reset tokens + if reqType == ResetPasswordTokenTypeInvite { + u.Path = fmt.Sprintf("/web/invite/%v", tokenID) + } else if reqType == ResetPasswordTokenTypePassword { + u.Path = fmt.Sprintf("/web/reset/%v", tokenID) + } + + return u.String(), nil +} + +func (s *AuthServer) deleteResetPasswordTokens(ctx context.Context, username string) error { + tokens, err := s.GetResetPasswordTokens(ctx) + if err != nil { + return trace.Wrap(err) + } + + for _, token := range tokens { + if token.GetUser() != username { + continue + } + + err = s.DeleteResetPasswordToken(ctx, token.GetName()) + if err != nil { + return trace.Wrap(err) + } + } + + return nil +} + +func newTOTPKeys(issuer string, accountName string) (key string, qr []byte, err error) { + // create totp key + otpKey, err := totp.Generate(totp.GenerateOpts{ + Issuer: issuer, + AccountName: accountName, + }) + if err != nil { + return "", nil, trace.Wrap(err) + } + + // create QR code + var otpQRBuf bytes.Buffer + otpImage, err := otpKey.Image(456, 456) + if err != nil { + return "", nil, trace.Wrap(err) + } + png.Encode(&otpQRBuf, otpImage) + + return otpKey.Secret(), otpQRBuf.Bytes(), nil +} diff --git a/lib/auth/resetpasswordtoken_test.go b/lib/auth/resetpasswordtoken_test.go new file mode 100644 index 0000000000000..b382a09e61361 --- /dev/null +++ b/lib/auth/resetpasswordtoken_test.go @@ -0,0 +1,168 @@ +/* +Copyright 2020 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 auth + +import ( + "context" + "fmt" + "time" + + authority "github.com/gravitational/teleport/lib/auth/testauthority" + "github.com/gravitational/teleport/lib/backend" + "github.com/gravitational/teleport/lib/backend/lite" + "github.com/gravitational/teleport/lib/defaults" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/utils" + + . "gopkg.in/check.v1" +) + +type ResetPasswordTokenTest struct { + bk backend.Backend + a *AuthServer +} + +var _ = fmt.Printf +var _ = Suite(&ResetPasswordTokenTest{}) + +func (s *ResetPasswordTokenTest) SetUpSuite(c *C) { + utils.InitLoggerForTests() +} + +func (s *ResetPasswordTokenTest) TearDownSuite(c *C) { +} + +func (s *ResetPasswordTokenTest) SetUpTest(c *C) { + var err error + c.Assert(err, IsNil) + s.bk, err = lite.New(context.TODO(), backend.Params{"path": c.MkDir()}) + c.Assert(err, IsNil) + + // set cluster name + clusterName, err := services.NewClusterName(services.ClusterNameSpecV2{ + ClusterName: "me.localhost", + }) + c.Assert(err, IsNil) + authConfig := &InitConfig{ + ClusterName: clusterName, + Backend: s.bk, + Authority: authority.New(), + SkipPeriodicOperations: true, + } + s.a, err = NewAuthServer(authConfig) + c.Assert(err, IsNil) + + err = s.a.SetClusterName(clusterName) + c.Assert(err, IsNil) + + // Set services.ClusterConfig to disallow local auth. + clusterConfig, err := services.NewClusterConfig(services.ClusterConfigSpecV3{ + LocalAuth: services.NewBool(true), + }) + c.Assert(err, IsNil) + + err = s.a.SetClusterConfig(clusterConfig) + c.Assert(err, IsNil) +} + +func (s *ResetPasswordTokenTest) TearDownTest(c *C) { +} + +func (s *ResetPasswordTokenTest) TestCreateResetPasswordToken(c *C) { + username := "joe@example.com" + pass := "pass123" + _, _, err := CreateUserAndRole(s.a, username, []string{username}) + c.Assert(err, IsNil) + + req := CreateResetPasswordTokenRequest{ + Name: username, + TTL: time.Hour, + } + + token, err := s.a.CreateResetPasswordToken(context.TODO(), req) + c.Assert(err, IsNil) + c.Assert(token.GetUser(), Equals, username) + c.Assert(token.GetURL(), Equals, "https://:3080/web/reset/"+token.GetName()) + + // verify that password was reset + err = s.a.CheckPasswordWOToken(username, []byte(pass)) + c.Assert(err, NotNil) + + // create another reset token for the same user + token, err = s.a.CreateResetPasswordToken(context.TODO(), req) + c.Assert(err, IsNil) + + // previous token must be deleted + tokens, err := s.a.GetResetPasswordTokens(context.TODO()) + c.Assert(err, IsNil) + c.Assert(len(tokens), Equals, 1) + c.Assert(tokens[0].GetName(), Equals, token.GetName()) +} + +func (s *ResetPasswordTokenTest) TestCreateResetPasswordTokenErrors(c *C) { + username := "joe@example.com" + _, _, err := CreateUserAndRole(s.a, username, []string{username}) + c.Assert(err, IsNil) + + type testCase struct { + desc string + req CreateResetPasswordTokenRequest + } + + testCases := []testCase{ + { + desc: "Reset Password: TTL < 0", + req: CreateResetPasswordTokenRequest{ + Name: username, + TTL: -1, + }, + }, + { + desc: "Reset Password: TTL > max", + req: CreateResetPasswordTokenRequest{ + Name: username, + TTL: defaults.MaxChangePasswordTokenTTL + time.Hour, + }, + }, + { + desc: "Reset Password: empty user name", + req: CreateResetPasswordTokenRequest{ + TTL: time.Hour, + }, + }, + { + desc: "Reset Password: user does not exist", + req: CreateResetPasswordTokenRequest{ + Name: "doesnotexist@example.com", + TTL: time.Hour, + }, + }, + { + desc: "Invite: TTL > max", + req: CreateResetPasswordTokenRequest{ + Name: username, + TTL: defaults.MaxSignupTokenTTL + time.Hour, + Type: ResetPasswordTokenTypeInvite, + }, + }, + } + + for _, tc := range testCases { + _, err := s.a.CreateResetPasswordToken(context.TODO(), tc.req) + c.Assert(err, NotNil, Commentf("test case %q", tc.desc)) + } +} diff --git a/lib/auth/tls_test.go b/lib/auth/tls_test.go index 9f3576cf7bbd9..2b35b624471d5 100644 --- a/lib/auth/tls_test.go +++ b/lib/auth/tls_test.go @@ -27,7 +27,6 @@ import ( "fmt" "io" "io/ioutil" - "net/url" "os" "path/filepath" "testing" @@ -50,7 +49,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" "github.com/pquerna/otp/totp" - "github.com/tstranex/u2f" "gopkg.in/check.v1" ) @@ -1206,13 +1204,6 @@ func (s *TLSSuite) TestOTPCRUD(c *check.C) { err = s.server.Auth().UpsertTOTP(user, otpSecret) c.Assert(err, check.IsNil) - // make sure the otp url we get back is valid url issued to the correct user - otpURL, _, err := s.server.Auth().GetOTPData(user) - c.Assert(err, check.IsNil) - u, err := url.Parse(otpURL) - c.Assert(err, check.IsNil) - c.Assert(u.Path, check.Equals, "/user1") - // a completely invalid token should return access denied err = clt.CheckPassword("user1", pass, "123456") c.Assert(err, check.NotNil) @@ -1765,14 +1756,6 @@ func (s *TLSSuite) TestAuthenticateWebUserOTP(c *check.C) { err = s.server.Auth().UpsertTOTP(user, otpSecret) c.Assert(err, check.IsNil) - otpURL, _, err := s.server.Auth().GetOTPData(user) - c.Assert(err, check.IsNil) - - // make sure label in url is correct - u, err := url.Parse(otpURL) - c.Assert(err, check.IsNil) - c.Assert(u.Path, check.Equals, "/ws-test") - // create a valid otp token validToken, err := totp.GenerateCode(otpSecret, s.server.Clock().Now()) c.Assert(err, check.IsNil) @@ -1831,68 +1814,6 @@ func (s *TLSSuite) TestAuthenticateWebUserOTP(c *check.C) { c.Assert(err, check.NotNil) } -// TestTokenSignupFlow tests signup flow using invite token -func (s *TLSSuite) TestTokenSignupFlow(c *check.C) { - authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ - Type: teleport.Local, - SecondFactor: teleport.OTP, - }) - c.Assert(err, check.IsNil) - err = s.server.Auth().SetAuthPreference(authPreference) - c.Assert(err, check.IsNil) - - user := "foobar" - mappings := []string{"admin", "db"} - - token, err := s.server.Auth().CreateSignupToken(services.UserV1{Name: user, AllowedLogins: mappings}, 0) - c.Assert(err, check.IsNil) - - proxy, err := s.server.NewClient(TestBuiltin(teleport.RoleProxy)) - c.Assert(err, check.IsNil) - - // invalid token - _, _, err = proxy.GetSignupTokenData("bad_token_data") - c.Assert(err, check.NotNil) - - // valid token - success - _, _, err = proxy.GetSignupTokenData(token) - c.Assert(err, check.IsNil) - - signupToken, err := s.server.Auth().GetSignupToken(token) - c.Assert(err, check.IsNil) - - otpToken, err := totp.GenerateCode(signupToken.OTPKey, s.server.Clock().Now()) - c.Assert(err, check.IsNil) - - // valid token, but missing second factor - newPassword := "abc123" - _, err = proxy.CreateUserWithoutOTP(token, newPassword) - fixtures.ExpectAccessDenied(c, err) - - // invalid signup token - _, err = proxy.CreateUserWithOTP("what_token?", newPassword, otpToken) - fixtures.ExpectAccessDenied(c, err) - - // valid signup token, invalid otp token - _, err = proxy.CreateUserWithOTP(token, newPassword, "badotp") - fixtures.ExpectAccessDenied(c, err) - - // success - ws, err := proxy.CreateUserWithOTP(token, newPassword, otpToken) - c.Assert(err, check.IsNil) - - // attempt to reuse token fails - _, err = proxy.CreateUserWithOTP(token, newPassword, otpToken) - fixtures.ExpectAccessDenied(c, err) - - // can login with web session credentials now - userClient, err := s.server.NewClientFromWebSession(ws) - c.Assert(err, check.IsNil) - - _, err = userClient.GetWebSessionInfo(user, ws.GetName()) - c.Assert(err, check.IsNil) -} - // TestLoginAttempts makes sure the login attempt counter is incremented and // reset correctly. func (s *TLSSuite) TestLoginAttempts(c *check.C) { @@ -1937,46 +1858,50 @@ func (s *TLSSuite) TestLoginAttempts(c *check.C) { c.Assert(loginAttempts, check.HasLen, 0) } -// TestSignupNoLocalAuth make sure that signup tokens can not be created -// when local auth is disabled. -func (s *TLSSuite) TestSignupNoLocalAuth(c *check.C) { - // Set services.ClusterConfig to disallow local auth. +func (s *TLSSuite) TestChangePasswordWithToken(c *check.C) { clusterConfig, err := services.NewClusterConfig(services.ClusterConfigSpecV3{ - LocalAuth: services.NewBool(false), + LocalAuth: services.NewBool(true), }) c.Assert(err, check.IsNil) + err = s.server.Auth().SetClusterConfig(clusterConfig) c.Assert(err, check.IsNil) - // Make sure access is denied when trying to create a signup token. - _, err = s.server.Auth().CreateSignupToken(services.UserV1{ - Name: "foo", - AllowedLogins: []string{"admin"}, - }, backend.Forever) - fixtures.ExpectAccessDenied(c, err) -} + authPreference, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OTP, + }) + c.Assert(err, check.IsNil) -// TestCreateUserNoLocalAuth make sure that local users can not be created -// when local auth is disabled. -func (s *TLSSuite) TestCreateUserNoLocalAuth(c *check.C) { - // Set services.ClusterConfig to disallow local auth. - clusterConfig, err := services.NewClusterConfig(services.ClusterConfigSpecV3{ - LocalAuth: services.NewBool(false), + err = s.server.Auth().SetAuthPreference(authPreference) + c.Assert(err, check.IsNil) + + username := "user1" + // Create a local user. + clt, err := s.server.NewClient(TestAdmin()) + c.Assert(err, check.IsNil) + + _, _, err = CreateUserAndRole(clt, username, []string{"role1"}) + c.Assert(err, check.IsNil) + + token, err := s.server.Auth().CreateResetPasswordToken(context.TODO(), CreateResetPasswordTokenRequest{ + Name: username, + TTL: time.Hour, }) c.Assert(err, check.IsNil) - err = s.server.Auth().SetClusterConfig(clusterConfig) + + secrets, err := s.server.Auth().RotateResetPasswordTokenSecrets(context.TODO(), token.GetName()) c.Assert(err, check.IsNil) - // Make sure access is denied when trying to create a user. - _, err = s.server.Auth().CreateUserWithoutOTP("foo", "bar") - fixtures.ExpectAccessDenied(c, err) - _, err = s.server.Auth().CreateUserWithOTP("foo", "bar", "123456") - fixtures.ExpectAccessDenied(c, err) - _, err = s.server.Auth().CreateUserWithU2FToken("foo", "bar", u2f.RegisterResponse{ - ClientData: "baz", - RegistrationData: "qux", + otpToken, err := totp.GenerateCode(secrets.GetOTPKey(), s.server.Clock().Now()) + c.Assert(err, check.IsNil) + + _, err = s.server.Auth().ChangePasswordWithToken(context.TODO(), ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + Password: []byte("qweqweqwe"), + SecondFactorToken: otpToken, }) - fixtures.ExpectAccessDenied(c, err) + c.Assert(err, check.IsNil) } // TestLoginNoLocalAuth makes sure that logins for local accounts can not be diff --git a/lib/auth/user.go b/lib/auth/user.go new file mode 100644 index 0000000000000..0ff678fe48037 --- /dev/null +++ b/lib/auth/user.go @@ -0,0 +1,84 @@ +/* +Copyright 2015 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 auth implements certificate signing authority and access control server +// Authority server is composed of several parts: +// +// * Authority server itself that implements signing and acl logic +// * HTTP server wrapper for authority server +// * HTTP client wrapper +// +package auth + +import ( + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/lib/events" + "github.com/gravitational/teleport/lib/services" + + "github.com/gravitational/trace" +) + +// UpsertUser upserts user +func (s *AuthServer) UpsertUser(user services.User) error { + err := s.Identity.UpsertUser(user) + if err != nil { + return trace.Wrap(err) + } + + // If the user was successfully upserted, emit an event. + var connectorName string + if user.GetCreatedBy().Connector == nil { + connectorName = teleport.Local + } else { + connectorName = user.GetCreatedBy().Connector.ID + } + s.EmitAuditEvent(events.UserUpdate, events.EventFields{ + events.EventUser: user.GetName(), + events.UserExpires: user.Expiry(), + events.UserRoles: user.GetRoles(), + events.UserConnector: connectorName, + }) + + return nil +} + +// DeleteUser deletes user +func (s *AuthServer) DeleteUser(user string) error { + role, err := s.Access.GetRole(services.RoleNameForUser(user)) + if err != nil { + if !trace.IsNotFound(err) { + return trace.Wrap(err) + } + } else { + if err := s.Access.DeleteRole(role.GetName()); err != nil { + if !trace.IsNotFound(err) { + return trace.Wrap(err) + } + } + } + + err = s.Identity.DeleteUser(user) + if err != nil { + return trace.Wrap(err) + } + + // If the user was successfully deleted, emit an event. + s.EmitAuditEvent(events.UserDelete, events.EventFields{ + events.EventUser: user, + }) + + return nil +} diff --git a/lib/defaults/defaults.go b/lib/defaults/defaults.go index a23ff1661a47c..0bf1d5223ab78 100644 --- a/lib/defaults/defaults.go +++ b/lib/defaults/defaults.go @@ -130,6 +130,15 @@ const ( // clients can reduce this time, not increase it MaxSignupTokenTTL = 48 * time.Hour + // MaxChangePasswordTokenTTL is a maximum TTL for password change token + MaxChangePasswordTokenTTL = 24 * time.Hour + + // ChangePasswordTokenTTL is a default password change token expiry time + ChangePasswordTokenTTL = 8 * time.Hour + + // ResetPasswordLength is the length of the reset user password + ResetPasswordLength = 16 + // ProvisioningTokenTTL is a the default TTL for server provisioning // tokens. When a user generates a token without an explicit TTL, this // value is used. diff --git a/lib/events/api.go b/lib/events/api.go index 42fb898ca8577..e8f248ed7c3d4 100644 --- a/lib/events/api.go +++ b/lib/events/api.go @@ -173,6 +173,13 @@ const ( // AccessRequestID is the ID of an access request. AccessRequestID = "id" + // ResetPasswordTokenCreateEvent is emitted when a new reset password token is created. + ResetPasswordTokenCreateEvent = "reset_password_token.create" + // ResetPasswordTokenTTL is TTL of reset password token. + ResetPasswordTokenTTL = "ttl" + // ResetPasswordTokenFor is a user name of reset password token. + ResetPasswordTokenFor = "entity" + // ExecEvent is an exec command executed by script or user on // the server side ExecEvent = "exec" diff --git a/lib/events/codes.go b/lib/events/codes.go index c2969548772e2..b5ea6c40473ad 100644 --- a/lib/events/codes.go +++ b/lib/events/codes.go @@ -176,6 +176,11 @@ var ( Name: SessionNetworkEvent, Code: SessionNetworkCode, } + // ResetPasswordTokenCreated is emitted when token is created. + ResetPasswordTokenCreated = Event{ + Name: ResetPasswordTokenCreateEvent, + Code: ResetPasswordTokenCreateCode, + } ) var ( @@ -239,4 +244,6 @@ var ( AccessRequestCreateCode = "T5000I" // AccessRequestUpdateCode is the access request state update code. AccessRequestUpdateCode = "T5001I" + // ResetPasswordTokenCreateCode is the token create event code. + ResetPasswordTokenCreateCode = "T6000I" ) diff --git a/lib/events/slice.pb.go b/lib/events/slice.pb.go index 7fb71eeb0749a..c2111b014f498 100644 --- a/lib/events/slice.pb.go +++ b/lib/events/slice.pb.go @@ -43,7 +43,7 @@ func (m *SessionSlice) Reset() { *m = SessionSlice{} } func (m *SessionSlice) String() string { return proto.CompactTextString(m) } func (*SessionSlice) ProtoMessage() {} func (*SessionSlice) Descriptor() ([]byte, []int) { - return fileDescriptor_slice_c27e90ee7997b6d0, []int{0} + return fileDescriptor_slice_fde4e6ff9bad9f4f, []int{0} } func (m *SessionSlice) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -104,7 +104,8 @@ func (m *SessionSlice) GetVersion() int64 { type SessionChunk struct { // Time is the occurence of this event Time int64 `protobuf:"varint,2,opt,name=Time,proto3" json:"Time,omitempty"` - // Data is captured data, contains event fields in case of event, session data otherwise + // Data is captured data, contains event fields in case of event, session data + // otherwise Data []byte `protobuf:"bytes,3,opt,name=Data,proto3" json:"Data,omitempty"` // EventType is event type EventType string `protobuf:"bytes,4,opt,name=EventType,proto3" json:"EventType,omitempty"` @@ -125,7 +126,7 @@ func (m *SessionChunk) Reset() { *m = SessionChunk{} } func (m *SessionChunk) String() string { return proto.CompactTextString(m) } func (*SessionChunk) ProtoMessage() {} func (*SessionChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_slice_c27e90ee7997b6d0, []int{1} + return fileDescriptor_slice_fde4e6ff9bad9f4f, []int{1} } func (m *SessionChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -972,9 +973,9 @@ var ( ErrIntOverflowSlice = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("slice.proto", fileDescriptor_slice_c27e90ee7997b6d0) } +func init() { proto.RegisterFile("slice.proto", fileDescriptor_slice_fde4e6ff9bad9f4f) } -var fileDescriptor_slice_c27e90ee7997b6d0 = []byte{ +var fileDescriptor_slice_fde4e6ff9bad9f4f = []byte{ // 329 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0xc1, 0x4e, 0xc2, 0x40, 0x10, 0x86, 0x59, 0x0b, 0x05, 0x16, 0x0e, 0x66, 0x43, 0xc8, 0x06, 0x4d, 0xd3, 0x70, 0xea, 0xc1, diff --git a/lib/events/slice.proto b/lib/events/slice.proto index 3b32d1be95a6f..c072cc69bb973 100644 --- a/lib/events/slice.proto +++ b/lib/events/slice.proto @@ -12,28 +12,28 @@ message SessionSlice { // Chunks is a list of submitted session chunks repeated SessionChunk Chunks = 3; // Version specifies session slice version - int64 Version = 4; + int64 Version = 4; } // SessionChunk is a chunk to be posted in the context of the session message SessionChunk { // Time is the occurence of this event - int64 Time = 2; - // Data is captured data, contains event fields in case of event, session data otherwise + int64 Time = 2; + // Data is captured data, contains event fields in case of event, session data + // otherwise bytes Data = 3; // EventType is event type - string EventType = 4; + string EventType = 4; // EventIndex is the event global index - int64 EventIndex = 5; + int64 EventIndex = 5; // Index is the autoincremented chunk index int64 ChunkIndex = 6; // Offset is an offset from the previous chunk in bytes - int64 Offset = 7; + int64 Offset = 7; // Delay is a delay from the previous event in milliseconds int64 Delay = 8; } service AuditLog { - rpc SubmitSessionSlice(stream SessionSlice) returns (google.protobuf.Empty) { - } + rpc SubmitSessionSlice(stream SessionSlice) returns (google.protobuf.Empty) {} } diff --git a/lib/services/identity.go b/lib/services/identity.go index 564617f819a3d..e52b94e740885 100644 --- a/lib/services/identity.go +++ b/lib/services/identity.go @@ -21,6 +21,7 @@ limitations under the License. package services import ( + "context" "fmt" "time" @@ -124,18 +125,6 @@ type Identity interface { // UpsertPassword upserts new password and OTP token UpsertPassword(user string, password []byte) error - // UpsertSignupToken upserts signup token - one time token that lets user to create a user account - UpsertSignupToken(token string, tokenData SignupToken, ttl time.Duration) error - - // GetSignupToken returns signup token data - GetSignupToken(token string) (*SignupToken, error) - - // GetSignupTokens returns a list of signup tokens - GetSignupTokens() ([]SignupToken, error) - - // DeleteSignupToken deletes signup token from the storage - DeleteSignupToken(token string) error - // UpsertU2FRegisterChallenge upserts a U2F challenge for a new user corresponding to the token UpsertU2FRegisterChallenge(token string, u2fChallenge *u2f.Challenge) error @@ -201,18 +190,42 @@ type Identity interface { // CreateGithubConnector creates a new Github connector CreateGithubConnector(connector GithubConnector) error + // UpsertGithubConnector creates or updates a new Github connector UpsertGithubConnector(connector GithubConnector) error + // GetGithubConnectors returns all configured Github connectors GetGithubConnectors(withSecrets bool) ([]GithubConnector, error) + // GetGithubConnector returns a Github connector by its name GetGithubConnector(name string, withSecrets bool) (GithubConnector, error) + // DeleteGithubConnector deletes a Github connector by its name DeleteGithubConnector(name string) error + // CreateGithubAuthRequest creates a new auth request for Github OAuth2 flow CreateGithubAuthRequest(req GithubAuthRequest) error + // GetGithubAuthRequest retrieves Github auth request by the token GetGithubAuthRequest(stateToken string) (*GithubAuthRequest, error) + + // CreateResetPasswordToken creates a token + CreateResetPasswordToken(ctx context.Context, resetPasswordToken ResetPasswordToken) (ResetPasswordToken, error) + + // DeleteResetPasswordToken deletes a token + DeleteResetPasswordToken(ctx context.Context, tokenID string) error + + // GetResetPasswordTokens returns tokens + GetResetPasswordTokens(ctx context.Context) ([]ResetPasswordToken, error) + + // GetResetPasswordToken returns a token + GetResetPasswordToken(ctx context.Context, tokenID string) (ResetPasswordToken, error) + + // UpsertResetPasswordTokenSecrets upserts token secrets + UpsertResetPasswordTokenSecrets(ctx context.Context, secrets ResetPasswordTokenSecrets) error + + // GetResetPasswordTokenSecrets returns token secrets + GetResetPasswordTokenSecrets(ctx context.Context, tokenID string) (ResetPasswordTokenSecrets, error) } // VerifyPassword makes sure password satisfies our requirements (relaxed), @@ -229,16 +242,6 @@ func VerifyPassword(password []byte) error { return nil } -// SignupToken stores metadata about user signup token -// is stored and generated when tctl add user is executed -type SignupToken struct { - Token string `json:"token"` - User UserV1 `json:"user"` - OTPKey string `json:"otp_key"` - OTPQRCode []byte `json:"otp_qr_code"` - Expires time.Time `json:"expires"` -} - const ExternalIdentitySchema = `{ "type": "object", "additionalProperties": false, @@ -308,7 +311,7 @@ func (r *GithubAuthRequest) SetExpiry(expires time.Time) { r.Expires = &expires } -// Expires returns object expiry setting. +// Expiry returns object expiry setting. func (r *GithubAuthRequest) Expiry() time.Time { if r.Expires == nil { return time.Time{} diff --git a/lib/services/invite.go b/lib/services/invite.go deleted file mode 100644 index ed803b5ccea56..0000000000000 --- a/lib/services/invite.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2019 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 services - -import ( - "time" -) - -// InviteTokenV3 is an invite token spec format V3 -type InviteTokenV3 struct { - // Kind is a resource kind - always resource. - Kind string `json:"kind"` - - // SubKind is a resource sub kind - SubKind string `json:"sub_kind,omitempty"` - - // Version is a resource version. - Version string `json:"version"` - - // Metadata is metadata about the resource. - Metadata Metadata `json:"metadata"` - - // Spec is a spec of the invite token - Spec InviteTokenSpecV3 `json:"spec"` -} - -// InviteTokenSpecV3 is a spec for invite token -type InviteTokenSpecV3 struct { - // URL is a helper invite token URL - URL string `json:"url"` -} - -// NewInviteToken returns a new instance of the invite token -func NewInviteToken(token, signupURL string, expires time.Time) *InviteTokenV3 { - tok := InviteTokenV3{ - Kind: KindInviteToken, - Version: V3, - Metadata: Metadata{ - Name: token, - }, - Spec: InviteTokenSpecV3{ - URL: signupURL, - }, - } - if !expires.IsZero() { - tok.Metadata.SetExpiry(expires) - } - return &tok -} diff --git a/lib/services/local/resetpasswordtoken.go b/lib/services/local/resetpasswordtoken.go new file mode 100644 index 0000000000000..533ef90a4133a --- /dev/null +++ b/lib/services/local/resetpasswordtoken.go @@ -0,0 +1,149 @@ +/* +Copyright 2015 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 local + +import ( + "bytes" + "context" + + "github.com/gravitational/teleport/lib/backend" + "github.com/gravitational/teleport/lib/services" + + "github.com/gravitational/trace" +) + +// GetResetPasswordTokens returns all ResetPasswordTokens +func (s *IdentityService) GetResetPasswordTokens(ctx context.Context) ([]services.ResetPasswordToken, error) { + startKey := backend.Key(passwordTokensPrefix) + result, err := s.GetRange(ctx, startKey, backend.RangeEnd(startKey), backend.NoLimit) + if err != nil { + return nil, trace.Wrap(err) + } + + var tokens []services.ResetPasswordToken + for _, item := range result.Items { + if !bytes.HasSuffix(item.Key, []byte(paramsPrefix)) { + continue + } + + token, err := services.GetResetPasswordTokenMarshaler().Unmarshal(item.Value) + if err != nil { + return nil, trace.Wrap(err) + } + + tokens = append(tokens, token) + } + + return tokens, nil +} + +// DeleteResetPasswordToken deletes ResetPasswordToken by ID +func (s *IdentityService) DeleteResetPasswordToken(ctx context.Context, tokenID string) error { + _, err := s.GetResetPasswordToken(ctx, tokenID) + if err != nil { + return trace.Wrap(err) + } + + startKey := backend.Key(passwordTokensPrefix, tokenID) + err = s.DeleteRange(ctx, startKey, backend.RangeEnd(startKey)) + return trace.Wrap(err) +} + +// GetResetPasswordToken returns a token by its ID +func (s *IdentityService) GetResetPasswordToken(ctx context.Context, tokenID string) (services.ResetPasswordToken, error) { + item, err := s.Get(ctx, backend.Key(passwordTokensPrefix, tokenID, paramsPrefix)) + if err != nil { + if trace.IsNotFound(err) { + return nil, trace.NotFound("reset password token(%v) not found", tokenID) + } + return nil, trace.Wrap(err) + } + + token, err := services.GetResetPasswordTokenMarshaler().Unmarshal(item.Value) + if err != nil { + return nil, trace.Wrap(err) + } + + return token, nil +} + +// CreateResetPasswordToken creates a token that is used for signups and resets +func (s *IdentityService) CreateResetPasswordToken(ctx context.Context, token services.ResetPasswordToken) (services.ResetPasswordToken, error) { + if err := token.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + + value, err := services.GetResetPasswordTokenMarshaler().Marshal(token) + if err != nil { + return nil, trace.Wrap(err) + } + + item := backend.Item{ + Key: backend.Key(passwordTokensPrefix, token.GetName(), paramsPrefix), + Value: value, + Expires: token.Expiry(), + } + _, err = s.Create(ctx, item) + if err != nil { + return nil, trace.Wrap(err) + } + + return token, nil +} + +// GetResetPasswordTokenSecrets returns token secrets +func (s *IdentityService) GetResetPasswordTokenSecrets(ctx context.Context, tokenID string) (services.ResetPasswordTokenSecrets, error) { + item, err := s.Get(ctx, backend.Key(passwordTokensPrefix, tokenID, secretsPrefix)) + if err != nil { + if trace.IsNotFound(err) { + return nil, trace.NotFound("reset password token(%v) secrets not found", tokenID) + } + return nil, trace.Wrap(err) + } + + secrets, err := services.UnmarshalResetPasswordTokenSecrets(item.Value) + if err != nil { + return nil, trace.Wrap(err) + } + + return secrets, nil +} + +// UpsertResetPasswordTokenSecrets upserts token secrets +func (s *IdentityService) UpsertResetPasswordTokenSecrets(ctx context.Context, secrets services.ResetPasswordTokenSecrets) error { + if err := secrets.CheckAndSetDefaults(); err != nil { + return trace.Wrap(err) + } + + value, err := services.MarshalResetPasswordTokenSecrets(secrets) + if err != nil { + return trace.Wrap(err) + } + item := backend.Item{ + Key: backend.Key(passwordTokensPrefix, secrets.GetName(), secretsPrefix), + Value: value, + Expires: secrets.Expiry(), + } + _, err = s.Put(ctx, item) + + return trace.Wrap(err) +} + +const ( + passwordTokensPrefix = "resetpasswordtokens" + secretsPrefix = "secrets" +) diff --git a/lib/services/local/users.go b/lib/services/local/users.go index b16167a2f25f8..721f90de7df5d 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -414,7 +414,7 @@ func (s *IdentityService) GetTOTP(user string) (string, error) { item, err := s.Get(context.TODO(), backend.Key(webPrefix, usersPrefix, user, totpPrefix)) if err != nil { if trace.IsNotFound(err) { - return "", trace.NotFound("user %q is not found", user) + return "", trace.NotFound("OTP key for user(%q) is not found", user) } return "", trace.Wrap(err) } @@ -593,74 +593,6 @@ func (s *IdentityService) UpsertPassword(user string, password []byte) error { return nil } -// UpsertSignupToken upserts signup token - one time token that lets user to create a user account -func (s *IdentityService) UpsertSignupToken(token string, tokenData services.SignupToken, ttl time.Duration) error { - if ttl < time.Second || ttl > defaults.MaxSignupTokenTTL { - ttl = defaults.MaxSignupTokenTTL - } - tokenData.Expires = time.Now().UTC().Add(ttl) - value, err := json.Marshal(tokenData) - if err != nil { - return trace.Wrap(err) - } - item := backend.Item{ - Key: backend.Key(userTokensPrefix, token), - Value: value, - Expires: tokenData.Expires, - } - _, err = s.Put(context.TODO(), item) - if err != nil { - return trace.Wrap(err) - } - return nil - -} - -// GetSignupToken returns signup token data -func (s *IdentityService) GetSignupToken(token string) (*services.SignupToken, error) { - if token == "" { - return nil, trace.BadParameter("missing token") - } - item, err := s.Get(context.TODO(), backend.Key(userTokensPrefix, token)) - if err != nil { - return nil, trace.Wrap(err) - } - var signupToken services.SignupToken - err = json.Unmarshal(item.Value, &signupToken) - if err != nil { - return nil, trace.Wrap(err) - } - return &signupToken, nil -} - -// GetSignupTokens returns all non-expired user tokens -func (s *IdentityService) GetSignupTokens() ([]services.SignupToken, error) { - startKey := backend.Key(userTokensPrefix) - result, err := s.GetRange(context.TODO(), startKey, backend.RangeEnd(startKey), backend.NoLimit) - if err != nil { - return nil, trace.Wrap(err) - } - tokens := make([]services.SignupToken, len(result.Items)) - for i, item := range result.Items { - var signupToken services.SignupToken - err = json.Unmarshal(item.Value, &signupToken) - if err != nil { - return nil, trace.Wrap(err) - } - tokens[i] = signupToken - } - return tokens, nil -} - -// DeleteSignupToken deletes signup token from the storage -func (s *IdentityService) DeleteSignupToken(token string) error { - if token == "" { - return trace.BadParameter("missing parameter token") - } - err := s.Delete(context.TODO(), backend.Key(userTokensPrefix, token)) - return trace.Wrap(err) -} - func (s *IdentityService) UpsertU2FRegisterChallenge(token string, u2fChallenge *u2f.Challenge) error { if token == "" { return trace.BadParameter("missing parmeter token") @@ -1243,7 +1175,6 @@ const ( samlPrefix = "saml" githubPrefix = "github" requestsPrefix = "requests" - userTokensPrefix = "addusertokens" u2fRegChalPrefix = "adduseru2fchallenges" usedTOTPPrefix = "used_totp" usedTOTPTTL = 30 * time.Second diff --git a/lib/services/resetpasswordtoken.go b/lib/services/resetpasswordtoken.go new file mode 100644 index 0000000000000..37d4dae56cec7 --- /dev/null +++ b/lib/services/resetpasswordtoken.go @@ -0,0 +1,210 @@ +/* +Copyright 2020 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 services + +import ( + "fmt" + "time" + + "github.com/gravitational/teleport/lib/defaults" + "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/trace" + "github.com/jonboulle/clockwork" +) + +// ResetPasswordToken represents a temporary token used to reset passwords +type ResetPasswordToken interface { + // Resource provides common resource properties + Resource + // GetUser returns User + GetUser() string + // GetCreated returns Created + GetCreated() time.Time + // GetURL returns URL + GetURL() string + // SetURL returns URL + SetURL(string) + // CheckAndSetDefaults checks and set default values for any missing fields. + CheckAndSetDefaults() error +} + +// GetName returns Name +func (u *ResetPasswordTokenV3) GetName() string { + return u.Metadata.Name +} + +// GetUser returns User +func (u *ResetPasswordTokenV3) GetUser() string { + return u.Spec.User +} + +// GetCreated returns Created +func (u *ResetPasswordTokenV3) GetCreated() time.Time { + return u.Spec.Created +} + +// GetURL returns URL +func (u *ResetPasswordTokenV3) GetURL() string { + return u.Spec.URL +} + +// SetURL sets URL +func (u *ResetPasswordTokenV3) SetURL(url string) { + u.Spec.URL = url +} + +// Expiry returns object expiry setting +func (u *ResetPasswordTokenV3) Expiry() time.Time { + return u.Metadata.Expiry() +} + +// SetExpiry sets object expiry +func (u *ResetPasswordTokenV3) SetExpiry(t time.Time) { + u.Metadata.SetExpiry(t) +} + +// SetTTL sets Expires header using current clock +func (u *ResetPasswordTokenV3) SetTTL(clock clockwork.Clock, ttl time.Duration) { + u.Metadata.SetTTL(clock, ttl) +} + +// GetMetadata returns object metadata +func (u *ResetPasswordTokenV3) GetMetadata() Metadata { + return u.Metadata +} + +// GetVersion returns resource version +func (u *ResetPasswordTokenV3) GetVersion() string { + return u.Version +} + +// GetKind returns resource kind +func (u *ResetPasswordTokenV3) GetKind() string { + return u.Kind +} + +// SetName sets the name of the resource +func (u *ResetPasswordTokenV3) SetName(name string) { + u.Metadata.Name = name +} + +// GetResourceID returns resource ID +func (u *ResetPasswordTokenV3) GetResourceID() int64 { + return u.Metadata.ID +} + +// SetResourceID sets resource ID +func (u *ResetPasswordTokenV3) SetResourceID(id int64) { + u.Metadata.ID = id +} + +// GetSubKind returns resource sub kind +func (u *ResetPasswordTokenV3) GetSubKind() string { + return u.SubKind +} + +// SetSubKind sets resource subkind +func (u *ResetPasswordTokenV3) SetSubKind(s string) { + u.SubKind = s +} + +// CheckAndSetDefaults checks and set default values for any missing fields. +func (u ResetPasswordTokenV3) CheckAndSetDefaults() error { + return u.Metadata.CheckAndSetDefaults() +} + +// // String represents a human readable version of the token +func (u *ResetPasswordTokenV3) String() string { + return fmt.Sprintf("ResetPasswordTokenV3(tokenID=%v, user=%v, expires at %v)", u.GetName(), u.Spec.User, u.Expiry()) +} + +// NewResetPasswordToken is a convenience wa to create a RemoteCluster resource. +func NewResetPasswordToken(tokenID string) ResetPasswordTokenV3 { + return ResetPasswordTokenV3{ + Kind: KindResetPasswordToken, + Version: V3, + Metadata: Metadata{ + Name: tokenID, + Namespace: defaults.Namespace, + }, + } +} + +// ResetPasswordTokenSpecV3Template is a template for V3 ResetPasswordToken JSON schema +const ResetPasswordTokenSpecV3Template = `{ + "type": "object", + "additionalProperties": false, + "properties": { + "user": { + "type": ["string"] + }, + "created": { + "type": ["string"] + }, + "url": { + "type": ["string"] + } + } +}` + +type TeleportResetPasswordTokenMarshaler struct{} + +// ResetPasswordTokenMarshaler implements marshal/unmarshal of ResetPasswordToken implementations +// mostly adds support for extended versions +type ResetPasswordTokenMarshaler interface { + // Marshal marshals token to binary representation + Marshal(t ResetPasswordToken, opts ...MarshalOption) ([]byte, error) + // Unmarshal unmarshals token from binary representation + Unmarshal(bytes []byte, opts ...MarshalOption) (ResetPasswordToken, error) +} + +var resetPasswordTokenMarshaler ResetPasswordTokenMarshaler = &TeleportResetPasswordTokenMarshaler{} + +// SetResetTokenMarshaler sets global ResetPasswordToken marshaler +func SetResetTokenMarshaler(m ResetPasswordTokenMarshaler) { + marshalerMutex.Lock() + defer marshalerMutex.Unlock() + resetPasswordTokenMarshaler = m +} + +// GetResetPasswordTokenMarshaler returns ResetPasswordToken marshaler +func GetResetPasswordTokenMarshaler() ResetPasswordTokenMarshaler { + marshalerMutex.Lock() + defer marshalerMutex.Unlock() + return resetPasswordTokenMarshaler +} + +// Unmarshal unmarshals ResetPasswordToken +func (t *TeleportResetPasswordTokenMarshaler) Unmarshal(bytes []byte, opts ...MarshalOption) (ResetPasswordToken, error) { + if len(bytes) == 0 { + return nil, trace.BadParameter("missing resource data") + } + + var token ResetPasswordTokenV3 + schema := fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ResetPasswordTokenSpecV3Template, DefaultDefinitions) + err := utils.UnmarshalWithSchema(schema, &token, bytes) + if err != nil { + return nil, trace.BadParameter(err.Error()) + } + + return &token, nil +} + +// Marshal marshals role to JSON or YAML. +func (t *TeleportResetPasswordTokenMarshaler) Marshal(token ResetPasswordToken, opts ...MarshalOption) ([]byte, error) { + return utils.FastMarshal(token) +} diff --git a/lib/services/resetpasswordtoken_test.go b/lib/services/resetpasswordtoken_test.go new file mode 100644 index 0000000000000..66e31293a82ae --- /dev/null +++ b/lib/services/resetpasswordtoken_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2020 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 services + +import ( + "fmt" + "time" + + "github.com/gravitational/teleport/lib/fixtures" + "github.com/gravitational/teleport/lib/utils" + + "gopkg.in/check.v1" +) + +type ResetPasswordTokenSuite struct{} + +var _ = check.Suite(&ResetPasswordTokenSuite{}) +var _ = fmt.Printf + +func (s *ResetPasswordTokenSuite) SetUpSuite(c *check.C) { + utils.InitLoggerForTests() +} + +func (s *ResetPasswordTokenSuite) TestUnmarshal(c *check.C) { + created, err := time.Parse(time.RFC3339, "2020-01-14T18:52:39.523076855Z") + c.Assert(err, check.IsNil) + + type testCase struct { + description string + input string + expected ResetPasswordToken + } + + testCases := []testCase{ + { + description: "simple case", + input: ` + { + "kind": "user_token", + "version": "v3", + "metadata": { + "name": "tokenId" + }, + "spec": { + "user": "example@example.com", + "created": "2020-01-14T18:52:39.523076855Z", + "url": "https://localhost" + } + } + `, + expected: &ResetPasswordTokenV3{ + Kind: KindResetPasswordToken, + Version: V3, + Metadata: Metadata{ + Name: "tokenId", + }, + Spec: ResetPasswordTokenSpecV3{ + Created: created, + User: "example@example.com", + URL: "https://localhost", + }, + }, + }, + } + + marshaler := GetResetPasswordTokenMarshaler() + for _, tc := range testCases { + comment := check.Commentf("test case %q", tc.description) + out, err := marshaler.Unmarshal([]byte(tc.input)) + c.Assert(err, check.IsNil, comment) + fixtures.DeepCompare(c, tc.expected, out) + data, err := marshaler.Marshal(out) + c.Assert(err, check.IsNil, comment) + out2, err := marshaler.Unmarshal(data) + c.Assert(err, check.IsNil, comment) + fixtures.DeepCompare(c, tc.expected, out2) + } +} diff --git a/lib/services/resetpasswordtokensecrets.go b/lib/services/resetpasswordtokensecrets.go new file mode 100644 index 0000000000000..4fd9586c20a53 --- /dev/null +++ b/lib/services/resetpasswordtokensecrets.go @@ -0,0 +1,230 @@ +/* +Copyright 2020 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 services + +import ( + "fmt" + "time" + + "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/trace" + "github.com/jonboulle/clockwork" +) + +// ResetPasswordTokenSecrets contains token secrets +type ResetPasswordTokenSecrets interface { + // Resource provides common resource properties + Resource + // GetCreated returns Created + GetCreated() time.Time + // GetQRCode returns QRCode + GetQRCode() []byte + // GetOTPKey returns OTP key + GetOTPKey() string + // CheckAndSetDefaults checks and set default values for any missing fields. + CheckAndSetDefaults() error +} + +// GetName returns Name +func (u *ResetPasswordTokenSecretsV3) GetName() string { + return u.Metadata.Name +} + +// GetCreated returns Created +func (u *ResetPasswordTokenSecretsV3) GetCreated() time.Time { + return u.Spec.Created +} + +// GetOTPKey returns OTP Key +func (u *ResetPasswordTokenSecretsV3) GetOTPKey() string { + return u.Spec.OTPKey +} + +// GetQRCode returns QRCode +func (u *ResetPasswordTokenSecretsV3) GetQRCode() []byte { + return []byte(u.Spec.QRCode) +} + +// Expiry returns object expiry setting +func (u *ResetPasswordTokenSecretsV3) Expiry() time.Time { + return u.Metadata.Expiry() +} + +// SetExpiry sets object expiry +func (u *ResetPasswordTokenSecretsV3) SetExpiry(t time.Time) { + u.Metadata.SetExpiry(t) +} + +// SetTTL sets Expires header using current clock +func (u *ResetPasswordTokenSecretsV3) SetTTL(clock clockwork.Clock, ttl time.Duration) { + u.Metadata.SetTTL(clock, ttl) +} + +// GetMetadata returns object metadata +func (u *ResetPasswordTokenSecretsV3) GetMetadata() Metadata { + return u.Metadata +} + +// GetVersion returns resource version +func (u *ResetPasswordTokenSecretsV3) GetVersion() string { + return u.Version +} + +// GetKind returns resource kind +func (u *ResetPasswordTokenSecretsV3) GetKind() string { + return u.Kind +} + +// SetName sets the name of the resource +func (u *ResetPasswordTokenSecretsV3) SetName(name string) { + u.Metadata.Name = name +} + +// GetResourceID returns resource ID +func (u *ResetPasswordTokenSecretsV3) GetResourceID() int64 { + return u.Metadata.ID +} + +// SetResourceID sets resource ID +func (u *ResetPasswordTokenSecretsV3) SetResourceID(id int64) { + u.Metadata.ID = id +} + +// GetSubKind returns resource sub kind +func (u *ResetPasswordTokenSecretsV3) GetSubKind() string { + return u.SubKind +} + +// SetSubKind sets resource subkind +func (u *ResetPasswordTokenSecretsV3) SetSubKind(s string) { + u.SubKind = s +} + +// CheckAndSetDefaults checks and set default values for any missing fields. +func (u ResetPasswordTokenSecretsV3) CheckAndSetDefaults() error { + return u.Metadata.CheckAndSetDefaults() +} + +// // String represents a human readable version of the token secrets +func (u *ResetPasswordTokenSecretsV3) String() string { + return fmt.Sprintf("ResetPasswordTokenSecretsV3(tokenID=%v, opt_key=%v, qr_code=%v)", u.GetName(), u.Spec.OTPKey, u.Spec.QRCode) +} + +// NewResetPasswordTokenSecrets creates an instance of ResetPasswordTokenSecrets +func NewResetPasswordTokenSecrets(tokenID string) (ResetPasswordTokenSecretsV3, error) { + secrets := ResetPasswordTokenSecretsV3{ + Kind: KindResetPasswordTokenSecrets, + Version: V3, + Metadata: Metadata{ + Name: tokenID, + }, + } + + err := secrets.CheckAndSetDefaults() + if err != nil { + return ResetPasswordTokenSecretsV3{}, trace.Wrap(err) + } + + return secrets, nil +} + +// ResetPasswordTokenSecretsSpecV3Template is a template for V3 ResetPasswordTokenSecrets JSON schema +const ResetPasswordTokenSecretsSpecV3Template = `{ + "type": "object", + "additionalProperties": false, + "properties": { + "opt_key": { + "type": ["string"] + }, + "qr_code": { + "type": ["string"] + }, + "created": { + "type": ["string"] + } + } +}` + +// UnmarshalResetPasswordTokenSecrets unmarshals ResetPasswordTokenSecrets +func UnmarshalResetPasswordTokenSecrets(bytes []byte) (ResetPasswordTokenSecrets, error) { + if len(bytes) == 0 { + return nil, trace.BadParameter("missing resource data") + } + + schema := fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ResetPasswordTokenSecretsSpecV3Template, DefaultDefinitions) + + var secrets ResetPasswordTokenSecretsV3 + err := utils.UnmarshalWithSchema(schema, &secrets, bytes) + if err != nil { + return nil, trace.BadParameter(err.Error()) + } + + return &secrets, nil +} + +// MarshalResetPasswordTokenSecrets marshals role to JSON or YAML. +func MarshalResetPasswordTokenSecrets(secrets ResetPasswordTokenSecrets, opts ...MarshalOption) ([]byte, error) { + return utils.FastMarshal(secrets) +} + +type TeleportResetPasswordTokenSecretsMarshaler struct{} + +// ResetPasswordTokenSecretsMarshaler implements marshal/unmarshal of ResetPasswordTokenSecrets implementations +// mostly adds support for extended versions +type ResetPasswordTokenSecretsMarshaler interface { + // Marshal marshals token to binary representation + Marshal(t ResetPasswordTokenSecrets, opts ...MarshalOption) ([]byte, error) + // Unmarshal unmarshals token from binary representation + Unmarshal(bytes []byte, opts ...MarshalOption) (ResetPasswordTokenSecrets, error) +} + +var resetPasswordTokenSecretsMarshaler ResetPasswordTokenSecretsMarshaler = &TeleportResetPasswordTokenSecretsMarshaler{} + +// SetResetTokenSecretsMarshaler sets global ResetPasswordTokenSecrets marshaler +func SetResetTokenSecretsMarshaler(m ResetPasswordTokenSecretsMarshaler) { + marshalerMutex.Lock() + defer marshalerMutex.Unlock() + resetPasswordTokenSecretsMarshaler = m +} + +// GetResetPasswordTokenSecretsMarshaler returns ResetPasswordTokenSecrets marshaler +func GetResetPasswordTokenSecretsMarshaler() ResetPasswordTokenSecretsMarshaler { + marshalerMutex.Lock() + defer marshalerMutex.Unlock() + return resetPasswordTokenSecretsMarshaler +} + +// Unmarshal unmarshals ResetPasswordTokenSecrets +func (t *TeleportResetPasswordTokenSecretsMarshaler) Unmarshal(bytes []byte, opts ...MarshalOption) (ResetPasswordTokenSecrets, error) { + if len(bytes) == 0 { + return nil, trace.BadParameter("missing resource data") + } + + var secrets ResetPasswordTokenSecretsV3 + schema := fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ResetPasswordTokenSecretsSpecV3Template, DefaultDefinitions) + err := utils.UnmarshalWithSchema(schema, &secrets, bytes) + if err != nil { + return nil, trace.BadParameter(err.Error()) + } + + return &secrets, nil +} + +// Marshal marshals role to JSON or YAML. +func (t *TeleportResetPasswordTokenSecretsMarshaler) Marshal(secrets ResetPasswordTokenSecrets, opts ...MarshalOption) ([]byte, error) { + return utils.FastMarshal(secrets) +} diff --git a/lib/services/resource.go b/lib/services/resource.go index 869ae4ae9dd7e..9ca4e4c743c46 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -162,8 +162,11 @@ const ( // to proxy KindRemoteCluster = "remote_cluster" - // KindInviteToken is a local user invite token - KindInviteToken = "invite_token" + // KindResetPasswordToken is a token used to change user passwords + KindResetPasswordToken = "user_token" + + // KindResetPasswordTokenSecrets is reset password token secrets + KindResetPasswordTokenSecrets = "reset_password_token_secrets" // KindIdentity is local on disk identity resource KindIdentity = "identity" diff --git a/lib/services/types.pb.go b/lib/services/types.pb.go index 41c28a6562064..4655c98568147 100644 --- a/lib/services/types.pb.go +++ b/lib/services/types.pb.go @@ -64,7 +64,7 @@ func (x RequestState) String() string { return proto.EnumName(RequestState_name, int32(x)) } func (RequestState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{0} + return fileDescriptor_types_62fad942422eb27d, []int{0} } type KeepAlive struct { @@ -85,7 +85,7 @@ func (m *KeepAlive) Reset() { *m = KeepAlive{} } func (m *KeepAlive) String() string { return proto.CompactTextString(m) } func (*KeepAlive) ProtoMessage() {} func (*KeepAlive) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{0} + return fileDescriptor_types_62fad942422eb27d, []int{0} } func (m *KeepAlive) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -125,7 +125,8 @@ type Metadata struct { Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"description,omitempty"` // Labels is a set of labels Labels map[string]string `protobuf:"bytes,5,rep,name=Labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // Expires is a global expiry time header can be set on any resource in the system. + // Expires is a global expiry time header can be set on any resource in the + // system. Expires *time.Time `protobuf:"bytes,6,opt,name=Expires,stdtime" json:"expires,omitempty"` // ID is a record ID ID int64 `protobuf:"varint,7,opt,name=ID,proto3" json:"id,omitempty"` @@ -138,7 +139,7 @@ func (m *Metadata) Reset() { *m = Metadata{} } func (m *Metadata) String() string { return proto.CompactTextString(m) } func (*Metadata) ProtoMessage() {} func (*Metadata) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{1} + return fileDescriptor_types_62fad942422eb27d, []int{1} } func (m *Metadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -197,7 +198,7 @@ type Rotation struct { func (m *Rotation) Reset() { *m = Rotation{} } func (*Rotation) ProtoMessage() {} func (*Rotation) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{2} + return fileDescriptor_types_62fad942422eb27d, []int{2} } func (m *Rotation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -244,7 +245,7 @@ func (m *RotationSchedule) Reset() { *m = RotationSchedule{} } func (m *RotationSchedule) String() string { return proto.CompactTextString(m) } func (*RotationSchedule) ProtoMessage() {} func (*RotationSchedule) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{3} + return fileDescriptor_types_62fad942422eb27d, []int{3} } func (m *RotationSchedule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -293,7 +294,7 @@ func (m *ResourceHeader) Reset() { *m = ResourceHeader{} } func (m *ResourceHeader) String() string { return proto.CompactTextString(m) } func (*ResourceHeader) ProtoMessage() {} func (*ResourceHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{4} + return fileDescriptor_types_62fad942422eb27d, []int{4} } func (m *ResourceHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -342,7 +343,7 @@ type ServerV2 struct { func (m *ServerV2) Reset() { *m = ServerV2{} } func (*ServerV2) ProtoMessage() {} func (*ServerV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{5} + return fileDescriptor_types_62fad942422eb27d, []int{5} } func (m *ServerV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -395,7 +396,7 @@ func (m *ServerSpecV2) Reset() { *m = ServerSpecV2{} } func (m *ServerSpecV2) String() string { return proto.CompactTextString(m) } func (*ServerSpecV2) ProtoMessage() {} func (*ServerSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{6} + return fileDescriptor_types_62fad942422eb27d, []int{6} } func (m *ServerSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -442,7 +443,7 @@ func (m *CommandLabelV2) Reset() { *m = CommandLabelV2{} } func (m *CommandLabelV2) String() string { return proto.CompactTextString(m) } func (*CommandLabelV2) ProtoMessage() {} func (*CommandLabelV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{7} + return fileDescriptor_types_62fad942422eb27d, []int{7} } func (m *CommandLabelV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -486,7 +487,7 @@ func (m *TLSKeyPair) Reset() { *m = TLSKeyPair{} } func (m *TLSKeyPair) String() string { return proto.CompactTextString(m) } func (*TLSKeyPair) ProtoMessage() {} func (*TLSKeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{8} + return fileDescriptor_types_62fad942422eb27d, []int{8} } func (m *TLSKeyPair) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -535,7 +536,7 @@ type CertAuthorityV2 struct { func (m *CertAuthorityV2) Reset() { *m = CertAuthorityV2{} } func (*CertAuthorityV2) ProtoMessage() {} func (*CertAuthorityV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{9} + return fileDescriptor_types_62fad942422eb27d, []int{9} } func (m *CertAuthorityV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -598,7 +599,7 @@ func (m *CertAuthoritySpecV2) Reset() { *m = CertAuthoritySpecV2{} } func (m *CertAuthoritySpecV2) String() string { return proto.CompactTextString(m) } func (*CertAuthoritySpecV2) ProtoMessage() {} func (*CertAuthoritySpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{10} + return fileDescriptor_types_62fad942422eb27d, []int{10} } func (m *CertAuthoritySpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -643,7 +644,7 @@ func (m *RoleMapping) Reset() { *m = RoleMapping{} } func (m *RoleMapping) String() string { return proto.CompactTextString(m) } func (*RoleMapping) ProtoMessage() {} func (*RoleMapping) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{11} + return fileDescriptor_types_62fad942422eb27d, []int{11} } func (m *RoleMapping) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -678,7 +679,8 @@ type ProvisionTokenV1 struct { // that will be converted to metadata in the SSH and X509 // certificates issued to the user of the token Roles []github_com_gravitational_teleport.Role `protobuf:"bytes,1,rep,name=Roles,casttype=github.com/gravitational/teleport.Role" json:"roles"` - // Expires is a global expiry time header can be set on any resource in the system. + // Expires is a global expiry time header can be set on any resource in the + // system. Expires time.Time `protobuf:"bytes,2,opt,name=Expires,stdtime" json:"expires,omitempty"` // Token is a token name Token string `protobuf:"bytes,3,opt,name=Token,proto3" json:"token"` @@ -690,7 +692,7 @@ type ProvisionTokenV1 struct { func (m *ProvisionTokenV1) Reset() { *m = ProvisionTokenV1{} } func (*ProvisionTokenV1) ProtoMessage() {} func (*ProvisionTokenV1) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{12} + return fileDescriptor_types_62fad942422eb27d, []int{12} } func (m *ProvisionTokenV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -739,7 +741,7 @@ type ProvisionTokenV2 struct { func (m *ProvisionTokenV2) Reset() { *m = ProvisionTokenV2{} } func (*ProvisionTokenV2) ProtoMessage() {} func (*ProvisionTokenV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{13} + return fileDescriptor_types_62fad942422eb27d, []int{13} } func (m *ProvisionTokenV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -783,7 +785,7 @@ func (m *ProvisionTokenSpecV2) Reset() { *m = ProvisionTokenSpecV2{} } func (m *ProvisionTokenSpecV2) String() string { return proto.CompactTextString(m) } func (*ProvisionTokenSpecV2) ProtoMessage() {} func (*ProvisionTokenSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{14} + return fileDescriptor_types_62fad942422eb27d, []int{14} } func (m *ProvisionTokenSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -832,7 +834,7 @@ type StaticTokensV2 struct { func (m *StaticTokensV2) Reset() { *m = StaticTokensV2{} } func (*StaticTokensV2) ProtoMessage() {} func (*StaticTokensV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{15} + return fileDescriptor_types_62fad942422eb27d, []int{15} } func (m *StaticTokensV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -875,7 +877,7 @@ func (m *StaticTokensSpecV2) Reset() { *m = StaticTokensSpecV2{} } func (m *StaticTokensSpecV2) String() string { return proto.CompactTextString(m) } func (*StaticTokensSpecV2) ProtoMessage() {} func (*StaticTokensSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{16} + return fileDescriptor_types_62fad942422eb27d, []int{16} } func (m *StaticTokensSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -924,7 +926,7 @@ type ClusterNameV2 struct { func (m *ClusterNameV2) Reset() { *m = ClusterNameV2{} } func (*ClusterNameV2) ProtoMessage() {} func (*ClusterNameV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{17} + return fileDescriptor_types_62fad942422eb27d, []int{17} } func (m *ClusterNameV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -967,7 +969,7 @@ func (m *ClusterNameSpecV2) Reset() { *m = ClusterNameSpecV2{} } func (m *ClusterNameSpecV2) String() string { return proto.CompactTextString(m) } func (*ClusterNameSpecV2) ProtoMessage() {} func (*ClusterNameSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{18} + return fileDescriptor_types_62fad942422eb27d, []int{18} } func (m *ClusterNameSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1016,7 +1018,7 @@ type ClusterConfigV3 struct { func (m *ClusterConfigV3) Reset() { *m = ClusterConfigV3{} } func (*ClusterConfigV3) ProtoMessage() {} func (*ClusterConfigV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{19} + return fileDescriptor_types_62fad942422eb27d, []int{19} } func (m *ClusterConfigV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1057,7 +1059,8 @@ type ClusterConfigSpecV3 struct { ProxyChecksHostKeys string `protobuf:"bytes,3,opt,name=ProxyChecksHostKeys,proto3" json:"proxy_checks_host_keys"` // Audit is a section with audit config Audit AuditConfig `protobuf:"bytes,4,opt,name=Audit" json:"audit"` - // ClientIdleTimeout sets global cluster default setting for client idle timeouts + // ClientIdleTimeout sets global cluster default setting for client idle + // timeouts ClientIdleTimeout Duration `protobuf:"varint,5,opt,name=ClientIdleTimeout,proto3,casttype=Duration" json:"client_idle_timeout"` // DisconnectExpiredCert provides disconnect expired certificate setting - // if true, connections with expired client certificates will get disconnected @@ -1065,7 +1068,8 @@ type ClusterConfigSpecV3 struct { // KeepAliveInterval is the interval the server sends keep-alive messsages // to the client at. KeepAliveInterval Duration `protobuf:"varint,7,opt,name=KeepAliveInterval,proto3,casttype=Duration" json:"keep_alive_interval"` - // KeepAliveCountMax is the number of keep-alive messages that can be missed before + // KeepAliveCountMax is the number of keep-alive messages that can be missed + // before // the server disconnects the connection to the client. KeepAliveCountMax int64 `protobuf:"varint,8,opt,name=KeepAliveCountMax,proto3" json:"keep_alive_count_max"` // LocalAuth is true if local authentication is enabled. @@ -1079,7 +1083,7 @@ func (m *ClusterConfigSpecV3) Reset() { *m = ClusterConfigSpecV3{} } func (m *ClusterConfigSpecV3) String() string { return proto.CompactTextString(m) } func (*ClusterConfigSpecV3) ProtoMessage() {} func (*ClusterConfigSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{20} + return fileDescriptor_types_62fad942422eb27d, []int{20} } func (m *ClusterConfigSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1132,7 +1136,7 @@ func (m *AuditConfig) Reset() { *m = AuditConfig{} } func (m *AuditConfig) String() string { return proto.CompactTextString(m) } func (*AuditConfig) ProtoMessage() {} func (*AuditConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{21} + return fileDescriptor_types_62fad942422eb27d, []int{21} } func (m *AuditConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1182,7 +1186,7 @@ func (m *Namespace) Reset() { *m = Namespace{} } func (m *Namespace) String() string { return proto.CompactTextString(m) } func (*Namespace) ProtoMessage() {} func (*Namespace) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{22} + return fileDescriptor_types_62fad942422eb27d, []int{22} } func (m *Namespace) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1222,7 +1226,7 @@ func (m *NamespaceSpec) Reset() { *m = NamespaceSpec{} } func (m *NamespaceSpec) String() string { return proto.CompactTextString(m) } func (*NamespaceSpec) ProtoMessage() {} func (*NamespaceSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{23} + return fileDescriptor_types_62fad942422eb27d, []int{23} } func (m *NamespaceSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1251,6 +1255,192 @@ func (m *NamespaceSpec) XXX_DiscardUnknown() { var xxx_messageInfo_NamespaceSpec proto.InternalMessageInfo +type ResetPasswordTokenV3 struct { + // Kind is a resource kind + Kind string `protobuf:"bytes,1,opt,name=Kind,proto3" json:"kind"` + // SubKind is an optional resource sub kind, used in some resources + SubKind string `protobuf:"bytes,2,opt,name=SubKind,proto3" json:"sub_kind,omitempty"` + // Version is version + Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"version"` + // Metadata is ResetPasswordToken metadata + Metadata Metadata `protobuf:"bytes,4,opt,name=Metadata" json:"metadata"` + // Spec is an ResetPasswordToken specification + Spec ResetPasswordTokenSpecV3 `protobuf:"bytes,5,opt,name=Spec" json:"spec"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResetPasswordTokenV3) Reset() { *m = ResetPasswordTokenV3{} } +func (*ResetPasswordTokenV3) ProtoMessage() {} +func (*ResetPasswordTokenV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_62fad942422eb27d, []int{24} +} +func (m *ResetPasswordTokenV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResetPasswordTokenV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResetPasswordTokenV3.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *ResetPasswordTokenV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetPasswordTokenV3.Merge(dst, src) +} +func (m *ResetPasswordTokenV3) XXX_Size() int { + return m.Size() +} +func (m *ResetPasswordTokenV3) XXX_DiscardUnknown() { + xxx_messageInfo_ResetPasswordTokenV3.DiscardUnknown(m) +} + +var xxx_messageInfo_ResetPasswordTokenV3 proto.InternalMessageInfo + +type ResetPasswordTokenSpecV3 struct { + // User is user name associated with this token + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // URL is this token URL + URL string `protobuf:"bytes,2,opt,name=URL,proto3" json:"url"` + // Created holds information about when the token was created + Created time.Time `protobuf:"bytes,4,opt,name=Created,stdtime" json:"created,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResetPasswordTokenSpecV3) Reset() { *m = ResetPasswordTokenSpecV3{} } +func (m *ResetPasswordTokenSpecV3) String() string { return proto.CompactTextString(m) } +func (*ResetPasswordTokenSpecV3) ProtoMessage() {} +func (*ResetPasswordTokenSpecV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_62fad942422eb27d, []int{25} +} +func (m *ResetPasswordTokenSpecV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResetPasswordTokenSpecV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResetPasswordTokenSpecV3.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *ResetPasswordTokenSpecV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetPasswordTokenSpecV3.Merge(dst, src) +} +func (m *ResetPasswordTokenSpecV3) XXX_Size() int { + return m.Size() +} +func (m *ResetPasswordTokenSpecV3) XXX_DiscardUnknown() { + xxx_messageInfo_ResetPasswordTokenSpecV3.DiscardUnknown(m) +} + +var xxx_messageInfo_ResetPasswordTokenSpecV3 proto.InternalMessageInfo + +type ResetPasswordTokenSecretsV3 struct { + // Kind is a resource kind + Kind string `protobuf:"bytes,1,opt,name=Kind,proto3" json:"kind"` + // SubKind is an optional resource sub kind, used in some resources + SubKind string `protobuf:"bytes,2,opt,name=SubKind,proto3" json:"sub_kind,omitempty"` + // Version is version + Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"version"` + // Metadata is ResetPasswordTokenSecrets metadata + Metadata Metadata `protobuf:"bytes,4,opt,name=Metadata" json:"metadata"` + // Spec is an ResetPasswordTokenSecrets specification + Spec ResetPasswordTokenSecretsSpecV3 `protobuf:"bytes,5,opt,name=Spec" json:"spec"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResetPasswordTokenSecretsV3) Reset() { *m = ResetPasswordTokenSecretsV3{} } +func (*ResetPasswordTokenSecretsV3) ProtoMessage() {} +func (*ResetPasswordTokenSecretsV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_62fad942422eb27d, []int{26} +} +func (m *ResetPasswordTokenSecretsV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResetPasswordTokenSecretsV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResetPasswordTokenSecretsV3.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *ResetPasswordTokenSecretsV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetPasswordTokenSecretsV3.Merge(dst, src) +} +func (m *ResetPasswordTokenSecretsV3) XXX_Size() int { + return m.Size() +} +func (m *ResetPasswordTokenSecretsV3) XXX_DiscardUnknown() { + xxx_messageInfo_ResetPasswordTokenSecretsV3.DiscardUnknown(m) +} + +var xxx_messageInfo_ResetPasswordTokenSecretsV3 proto.InternalMessageInfo + +type ResetPasswordTokenSecretsSpecV3 struct { + // OTPKey is is a secret value of one time password secret generator + OTPKey string `protobuf:"bytes,1,opt,name=OTPKey,proto3" json:"opt_key"` + // OTPKey is is a secret value of one time password secret generator + QRCode string `protobuf:"bytes,2,opt,name=QRCode,proto3" json:"qr_code,omitempty"` + // Created holds information about when the token was created + Created time.Time `protobuf:"bytes,3,opt,name=Created,stdtime" json:"created,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResetPasswordTokenSecretsSpecV3) Reset() { *m = ResetPasswordTokenSecretsSpecV3{} } +func (m *ResetPasswordTokenSecretsSpecV3) String() string { return proto.CompactTextString(m) } +func (*ResetPasswordTokenSecretsSpecV3) ProtoMessage() {} +func (*ResetPasswordTokenSecretsSpecV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_62fad942422eb27d, []int{27} +} +func (m *ResetPasswordTokenSecretsSpecV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResetPasswordTokenSecretsSpecV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResetPasswordTokenSecretsSpecV3.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *ResetPasswordTokenSecretsSpecV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetPasswordTokenSecretsSpecV3.Merge(dst, src) +} +func (m *ResetPasswordTokenSecretsSpecV3) XXX_Size() int { + return m.Size() +} +func (m *ResetPasswordTokenSecretsSpecV3) XXX_DiscardUnknown() { + xxx_messageInfo_ResetPasswordTokenSecretsSpecV3.DiscardUnknown(m) +} + +var xxx_messageInfo_ResetPasswordTokenSecretsSpecV3 proto.InternalMessageInfo + // AccessRequest represents an access request resource specification type AccessRequestV3 struct { // Kind is a resource kind @@ -1271,7 +1461,7 @@ type AccessRequestV3 struct { func (m *AccessRequestV3) Reset() { *m = AccessRequestV3{} } func (*AccessRequestV3) ProtoMessage() {} func (*AccessRequestV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{24} + return fileDescriptor_types_62fad942422eb27d, []int{28} } func (m *AccessRequestV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1308,9 +1498,11 @@ type AccessRequestSpecV3 struct { Roles []string `protobuf:"bytes,2,rep,name=Roles" json:"roles"` // State is the current state of this access request. State RequestState `protobuf:"varint,3,opt,name=State,proto3,enum=services.RequestState" json:"state,omitempty"` - // Created encodes the time at which the request was registered with the auth server. + // Created encodes the time at which the request was registered with the auth + // server. Created time.Time `protobuf:"bytes,4,opt,name=Created,stdtime" json:"created,omitempty"` - // Expires constrains the maximum lifetime of any login session for which this request is active. + // Expires constrains the maximum lifetime of any login session for which this + // request is active. Expires time.Time `protobuf:"bytes,5,opt,name=Expires,stdtime" json:"expires,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1321,7 +1513,7 @@ func (m *AccessRequestSpecV3) Reset() { *m = AccessRequestSpecV3{} } func (m *AccessRequestSpecV3) String() string { return proto.CompactTextString(m) } func (*AccessRequestSpecV3) ProtoMessage() {} func (*AccessRequestSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{25} + return fileDescriptor_types_62fad942422eb27d, []int{29} } func (m *AccessRequestSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1559,7 @@ func (m *AccessRequestFilter) Reset() { *m = AccessRequestFilter{} } func (m *AccessRequestFilter) String() string { return proto.CompactTextString(m) } func (*AccessRequestFilter) ProtoMessage() {} func (*AccessRequestFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{26} + return fileDescriptor_types_62fad942422eb27d, []int{30} } func (m *AccessRequestFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1416,7 +1608,7 @@ type RoleV3 struct { func (m *RoleV3) Reset() { *m = RoleV3{} } func (*RoleV3) ProtoMessage() {} func (*RoleV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{27} + return fileDescriptor_types_62fad942422eb27d, []int{31} } func (m *RoleV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1643,8 @@ type RoleSpecV3 struct { Options RoleOptions `protobuf:"bytes,1,opt,name=Options" json:"options,omitempty"` // Allow is the set of conditions evaluated to grant access. Allow RoleConditions `protobuf:"bytes,2,opt,name=Allow" json:"allow,omitempty"` - // Deny is the set of conditions evaluated to deny access. Deny takes priority over allow. + // Deny is the set of conditions evaluated to deny access. Deny takes priority + // over allow. Deny RoleConditions `protobuf:"bytes,3,opt,name=Deny" json:"deny,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1462,7 +1655,7 @@ func (m *RoleSpecV3) Reset() { *m = RoleSpecV3{} } func (m *RoleSpecV3) String() string { return proto.CompactTextString(m) } func (*RoleSpecV3) ProtoMessage() {} func (*RoleSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{28} + return fileDescriptor_types_62fad942422eb27d, []int{32} } func (m *RoleSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1497,7 +1690,8 @@ type RoleOptions struct { ForwardAgent Bool `protobuf:"varint,1,opt,name=ForwardAgent,proto3,casttype=Bool" json:"forward_agent"` // MaxSessionTTL defines how long a SSH session can last for. MaxSessionTTL Duration `protobuf:"varint,2,opt,name=MaxSessionTTL,proto3,casttype=Duration" json:"max_session_ttl,omitempty"` - // PortForwarding defines if the certificate will have "permit-port-forwarding" + // PortForwarding defines if the certificate will have + // "permit-port-forwarding" // in the certificate. PortForwarding is "yes" if not set, // that's why this is a pointer PortForwarding *BoolOption `protobuf:"bytes,3,opt,name=PortForwarding,customtype=BoolOption" json:"port_forwarding,omitempty"` @@ -1521,7 +1715,7 @@ func (m *RoleOptions) Reset() { *m = RoleOptions{} } func (m *RoleOptions) String() string { return proto.CompactTextString(m) } func (*RoleOptions) ProtoMessage() {} func (*RoleOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{29} + return fileDescriptor_types_62fad942422eb27d, []int{33} } func (m *RoleOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1558,7 +1752,8 @@ type RoleConditions struct { // Namespaces is a list of namespaces (used to partition a cluster). The // field should be called "namespaces" when it returns in Teleport 2.4. Namespaces []string `protobuf:"bytes,2,rep,name=Namespaces" json:"-"` - // NodeLabels is a map of node labels (used to dynamically grant access to nodes). + // NodeLabels is a map of node labels (used to dynamically grant access to + // nodes). NodeLabels Labels `protobuf:"bytes,3,opt,name=NodeLabels,customtype=Labels" json:"node_labels,omitempty"` // Rules is a list of rules and their access levels. Rules are a high level // construct used for access control. @@ -1575,7 +1770,7 @@ func (m *RoleConditions) Reset() { *m = RoleConditions{} } func (m *RoleConditions) String() string { return proto.CompactTextString(m) } func (*RoleConditions) ProtoMessage() {} func (*RoleConditions) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{30} + return fileDescriptor_types_62fad942422eb27d, []int{34} } func (m *RoleConditions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1604,7 +1799,8 @@ func (m *RoleConditions) XXX_DiscardUnknown() { var xxx_messageInfo_RoleConditions proto.InternalMessageInfo -// AccessRequestConditions is a matcher for allow/deny restrictions on access-requests. +// AccessRequestConditions is a matcher for allow/deny restrictions on +// access-requests. type AccessRequestConditions struct { // Roles is the name of roles which will match the request rule. Roles []string `protobuf:"bytes,1,rep,name=Roles" json:"roles,omitempty"` @@ -1617,7 +1813,7 @@ func (m *AccessRequestConditions) Reset() { *m = AccessRequestConditions func (m *AccessRequestConditions) String() string { return proto.CompactTextString(m) } func (*AccessRequestConditions) ProtoMessage() {} func (*AccessRequestConditions) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{31} + return fileDescriptor_types_62fad942422eb27d, []int{35} } func (m *AccessRequestConditions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1666,7 +1862,7 @@ func (m *Rule) Reset() { *m = Rule{} } func (m *Rule) String() string { return proto.CompactTextString(m) } func (*Rule) ProtoMessage() {} func (*Rule) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{32} + return fileDescriptor_types_62fad942422eb27d, []int{36} } func (m *Rule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1708,7 +1904,7 @@ func (m *BoolValue) Reset() { *m = BoolValue{} } func (m *BoolValue) String() string { return proto.CompactTextString(m) } func (*BoolValue) ProtoMessage() {} func (*BoolValue) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{33} + return fileDescriptor_types_62fad942422eb27d, []int{37} } func (m *BoolValue) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1757,7 +1953,7 @@ type UserV2 struct { func (m *UserV2) Reset() { *m = UserV2{} } func (*UserV2) ProtoMessage() {} func (*UserV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{34} + return fileDescriptor_types_62fad942422eb27d, []int{38} } func (m *UserV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1809,7 +2005,8 @@ type UserSpecV2 struct { Expires time.Time `protobuf:"bytes,7,opt,name=Expires,stdtime" json:"expires"` // CreatedBy holds information about agent or person created this user CreatedBy CreatedBy `protobuf:"bytes,8,opt,name=CreatedBy" json:"created_by,omitempty"` - // LocalAuths hold sensitive data necessary for performing local authentication + // LocalAuths hold sensitive data necessary for performing local + // authentication LocalAuth *LocalAuthSecrets `protobuf:"bytes,9,opt,name=LocalAuth" json:"local_auth,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1820,7 +2017,7 @@ func (m *UserSpecV2) Reset() { *m = UserSpecV2{} } func (m *UserSpecV2) String() string { return proto.CompactTextString(m) } func (*UserSpecV2) ProtoMessage() {} func (*UserSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{35} + return fileDescriptor_types_62fad942422eb27d, []int{39} } func (m *UserSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1865,7 +2062,7 @@ type ExternalIdentity struct { func (m *ExternalIdentity) Reset() { *m = ExternalIdentity{} } func (*ExternalIdentity) ProtoMessage() {} func (*ExternalIdentity) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{36} + return fileDescriptor_types_62fad942422eb27d, []int{40} } func (m *ExternalIdentity) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1913,7 +2110,7 @@ func (m *LoginStatus) Reset() { *m = LoginStatus{} } func (m *LoginStatus) String() string { return proto.CompactTextString(m) } func (*LoginStatus) ProtoMessage() {} func (*LoginStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{37} + return fileDescriptor_types_62fad942422eb27d, []int{41} } func (m *LoginStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1958,7 +2155,7 @@ type CreatedBy struct { func (m *CreatedBy) Reset() { *m = CreatedBy{} } func (*CreatedBy) ProtoMessage() {} func (*CreatedBy) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{38} + return fileDescriptor_types_62fad942422eb27d, []int{42} } func (m *CreatedBy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2004,7 +2201,7 @@ func (m *U2FRegistrationData) Reset() { *m = U2FRegistrationData{} } func (m *U2FRegistrationData) String() string { return proto.CompactTextString(m) } func (*U2FRegistrationData) ProtoMessage() {} func (*U2FRegistrationData) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{39} + return fileDescriptor_types_62fad942422eb27d, []int{43} } func (m *U2FRegistrationData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2041,7 +2238,8 @@ type LocalAuthSecrets struct { TOTPKey string `protobuf:"bytes,2,opt,name=TOTPKey,proto3" json:"totp_key,omitempty"` // U2FRegistration holds Universal Second Factor registration info. U2FRegistration *U2FRegistrationData `protobuf:"bytes,3,opt,name=U2FRegistration" json:"u2f_registration,omitempty"` - // U2FCounter holds the highest seen Universal Second Factor registration count. + // U2FCounter holds the highest seen Universal Second Factor registration + // count. U2FCounter uint32 `protobuf:"varint,4,opt,name=U2FCounter,proto3" json:"u2f_counter,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -2052,7 +2250,7 @@ func (m *LocalAuthSecrets) Reset() { *m = LocalAuthSecrets{} } func (m *LocalAuthSecrets) String() string { return proto.CompactTextString(m) } func (*LocalAuthSecrets) ProtoMessage() {} func (*LocalAuthSecrets) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{40} + return fileDescriptor_types_62fad942422eb27d, []int{44} } func (m *LocalAuthSecrets) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2098,7 +2296,7 @@ func (m *ConnectorRef) Reset() { *m = ConnectorRef{} } func (m *ConnectorRef) String() string { return proto.CompactTextString(m) } func (*ConnectorRef) ProtoMessage() {} func (*ConnectorRef) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{41} + return fileDescriptor_types_62fad942422eb27d, []int{45} } func (m *ConnectorRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2140,7 +2338,7 @@ func (m *UserRef) Reset() { *m = UserRef{} } func (m *UserRef) String() string { return proto.CompactTextString(m) } func (*UserRef) ProtoMessage() {} func (*UserRef) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{42} + return fileDescriptor_types_62fad942422eb27d, []int{46} } func (m *UserRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2190,7 +2388,7 @@ func (m *ReverseTunnelV2) Reset() { *m = ReverseTunnelV2{} } func (m *ReverseTunnelV2) String() string { return proto.CompactTextString(m) } func (*ReverseTunnelV2) ProtoMessage() {} func (*ReverseTunnelV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{43} + return fileDescriptor_types_62fad942422eb27d, []int{47} } func (m *ReverseTunnelV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2237,7 +2435,7 @@ func (m *ReverseTunnelSpecV2) Reset() { *m = ReverseTunnelSpecV2{} } func (m *ReverseTunnelSpecV2) String() string { return proto.CompactTextString(m) } func (*ReverseTunnelSpecV2) ProtoMessage() {} func (*ReverseTunnelSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{44} + return fileDescriptor_types_62fad942422eb27d, []int{48} } func (m *ReverseTunnelSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2286,7 +2484,7 @@ type TunnelConnectionV2 struct { func (m *TunnelConnectionV2) Reset() { *m = TunnelConnectionV2{} } func (*TunnelConnectionV2) ProtoMessage() {} func (*TunnelConnectionV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{45} + return fileDescriptor_types_62fad942422eb27d, []int{49} } func (m *TunnelConnectionV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2334,7 +2532,7 @@ func (m *TunnelConnectionSpecV2) Reset() { *m = TunnelConnectionSpecV2{} func (m *TunnelConnectionSpecV2) String() string { return proto.CompactTextString(m) } func (*TunnelConnectionSpecV2) ProtoMessage() {} func (*TunnelConnectionSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c96a02d876242e74, []int{46} + return fileDescriptor_types_62fad942422eb27d, []int{50} } func (m *TunnelConnectionSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2390,6 +2588,10 @@ func init() { proto.RegisterType((*AuditConfig)(nil), "services.AuditConfig") proto.RegisterType((*Namespace)(nil), "services.Namespace") proto.RegisterType((*NamespaceSpec)(nil), "services.NamespaceSpec") + proto.RegisterType((*ResetPasswordTokenV3)(nil), "services.ResetPasswordTokenV3") + proto.RegisterType((*ResetPasswordTokenSpecV3)(nil), "services.ResetPasswordTokenSpecV3") + proto.RegisterType((*ResetPasswordTokenSecretsV3)(nil), "services.ResetPasswordTokenSecretsV3") + proto.RegisterType((*ResetPasswordTokenSecretsSpecV3)(nil), "services.ResetPasswordTokenSecretsSpecV3") proto.RegisterType((*AccessRequestV3)(nil), "services.AccessRequestV3") proto.RegisterType((*AccessRequestSpecV3)(nil), "services.AccessRequestSpecV3") proto.RegisterType((*AccessRequestFilter)(nil), "services.AccessRequestFilter") @@ -3688,7 +3890,7 @@ func (m *NamespaceSpec) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *AccessRequestV3) Marshal() (dAtA []byte, err error) { +func (m *ResetPasswordTokenV3) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3698,7 +3900,7 @@ func (m *AccessRequestV3) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *AccessRequestV3) MarshalTo(dAtA []byte) (int, error) { +func (m *ResetPasswordTokenV3) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -3743,7 +3945,7 @@ func (m *AccessRequestV3) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *AccessRequestSpecV3) Marshal() (dAtA []byte, err error) { +func (m *ResetPasswordTokenSpecV3) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3753,7 +3955,7 @@ func (m *AccessRequestSpecV3) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *AccessRequestSpecV3) MarshalTo(dAtA []byte) (int, error) { +func (m *ResetPasswordTokenSpecV3) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -3764,25 +3966,11 @@ func (m *AccessRequestSpecV3) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) i += copy(dAtA[i:], m.User) } - if len(m.Roles) > 0 { - for _, s := range m.Roles { - dAtA[i] = 0x12 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } - } - if m.State != 0 { - dAtA[i] = 0x18 + if len(m.URL) > 0 { + dAtA[i] = 0x12 i++ - i = encodeVarintTypes(dAtA, i, uint64(m.State)) + i = encodeVarintTypes(dAtA, i, uint64(len(m.URL))) + i += copy(dAtA[i:], m.URL) } dAtA[i] = 0x22 i++ @@ -3792,21 +3980,68 @@ func (m *AccessRequestSpecV3) MarshalTo(dAtA []byte) (int, error) { return 0, err } i += n32 - dAtA[i] = 0x2a + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *ResetPasswordTokenSecretsV3) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResetPasswordTokenSecretsV3) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Kind) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Kind))) + i += copy(dAtA[i:], m.Kind) + } + if len(m.SubKind) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.SubKind))) + i += copy(dAtA[i:], m.SubKind) + } + if len(m.Version) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Version))) + i += copy(dAtA[i:], m.Version) + } + dAtA[i] = 0x22 i++ - i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires))) - n33, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) + i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) + n33, err := m.Metadata.MarshalTo(dAtA[i:]) if err != nil { return 0, err } i += n33 + dAtA[i] = 0x2a + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) + n34, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n34 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } return i, nil } -func (m *AccessRequestFilter) Marshal() (dAtA []byte, err error) { +func (m *ResetPasswordTokenSecretsSpecV3) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3816,35 +4051,38 @@ func (m *AccessRequestFilter) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *AccessRequestFilter) MarshalTo(dAtA []byte) (int, error) { +func (m *ResetPasswordTokenSecretsSpecV3) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - if len(m.ID) > 0 { + if len(m.OTPKey) > 0 { dAtA[i] = 0xa i++ - i = encodeVarintTypes(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OTPKey))) + i += copy(dAtA[i:], m.OTPKey) } - if len(m.User) > 0 { + if len(m.QRCode) > 0 { dAtA[i] = 0x12 i++ - i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) - i += copy(dAtA[i:], m.User) + i = encodeVarintTypes(dAtA, i, uint64(len(m.QRCode))) + i += copy(dAtA[i:], m.QRCode) } - if m.State != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintTypes(dAtA, i, uint64(m.State)) + dAtA[i] = 0x1a + i++ + i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Created))) + n35, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Created, dAtA[i:]) + if err != nil { + return 0, err } + i += n35 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } return i, nil } -func (m *RoleV3) Marshal() (dAtA []byte, err error) { +func (m *AccessRequestV3) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3854,7 +4092,7 @@ func (m *RoleV3) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RoleV3) MarshalTo(dAtA []byte) (int, error) { +func (m *AccessRequestV3) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -3880,26 +4118,26 @@ func (m *RoleV3) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) - n34, err := m.Metadata.MarshalTo(dAtA[i:]) + n36, err := m.Metadata.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n34 + i += n36 dAtA[i] = 0x2a i++ i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) - n35, err := m.Spec.MarshalTo(dAtA[i:]) + n37, err := m.Spec.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n35 + i += n37 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } return i, nil } -func (m *RoleSpecV3) Marshal() (dAtA []byte, err error) { +func (m *AccessRequestSpecV3) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3909,42 +4147,60 @@ func (m *RoleSpecV3) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RoleSpecV3) MarshalTo(dAtA []byte) (int, error) { +func (m *AccessRequestSpecV3) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintTypes(dAtA, i, uint64(m.Options.Size())) - n36, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) } - i += n36 - dAtA[i] = 0x12 + if len(m.Roles) > 0 { + for _, s := range m.Roles { + dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + if m.State != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.State)) + } + dAtA[i] = 0x22 i++ - i = encodeVarintTypes(dAtA, i, uint64(m.Allow.Size())) - n37, err := m.Allow.MarshalTo(dAtA[i:]) + i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Created))) + n38, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Created, dAtA[i:]) if err != nil { return 0, err } - i += n37 - dAtA[i] = 0x1a + i += n38 + dAtA[i] = 0x2a i++ - i = encodeVarintTypes(dAtA, i, uint64(m.Deny.Size())) - n38, err := m.Deny.MarshalTo(dAtA[i:]) + i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires))) + n39, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) if err != nil { return 0, err } - i += n38 + i += n39 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } return i, nil } -func (m *RoleOptions) Marshal() (dAtA []byte, err error) { +func (m *AccessRequestFilter) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3954,12 +4210,150 @@ func (m *RoleOptions) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RoleOptions) MarshalTo(dAtA []byte) (int, error) { +func (m *AccessRequestFilter) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - if m.ForwardAgent { + if len(m.ID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.ID))) + i += copy(dAtA[i:], m.ID) + } + if len(m.User) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if m.State != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.State)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *RoleV3) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoleV3) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Kind) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Kind))) + i += copy(dAtA[i:], m.Kind) + } + if len(m.SubKind) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.SubKind))) + i += copy(dAtA[i:], m.SubKind) + } + if len(m.Version) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Version))) + i += copy(dAtA[i:], m.Version) + } + dAtA[i] = 0x22 + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) + n40, err := m.Metadata.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n40 + dAtA[i] = 0x2a + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) + n41, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n41 + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *RoleSpecV3) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoleSpecV3) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Options.Size())) + n42, err := m.Options.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n42 + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Allow.Size())) + n43, err := m.Allow.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n43 + dAtA[i] = 0x1a + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Deny.Size())) + n44, err := m.Deny.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n44 + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *RoleOptions) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoleOptions) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.ForwardAgent { dAtA[i] = 0x8 i++ if m.ForwardAgent { @@ -3978,11 +4372,11 @@ func (m *RoleOptions) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(m.PortForwarding.Size())) - n39, err := m.PortForwarding.MarshalTo(dAtA[i:]) + n45, err := m.PortForwarding.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n39 + i += n45 } if len(m.CertificateFormat) > 0 { dAtA[i] = 0x22 @@ -4074,11 +4468,11 @@ func (m *RoleConditions) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(m.NodeLabels.Size())) - n40, err := m.NodeLabels.MarshalTo(dAtA[i:]) + n46, err := m.NodeLabels.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n40 + i += n46 if len(m.Rules) > 0 { for _, msg := range m.Rules { dAtA[i] = 0x22 @@ -4110,11 +4504,11 @@ func (m *RoleConditions) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x32 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Request.Size())) - n41, err := m.Request.MarshalTo(dAtA[i:]) + n47, err := m.Request.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n41 + i += n47 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -4297,19 +4691,19 @@ func (m *UserV2) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) - n42, err := m.Metadata.MarshalTo(dAtA[i:]) + n48, err := m.Metadata.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n42 + i += n48 dAtA[i] = 0x2a i++ i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) - n43, err := m.Spec.MarshalTo(dAtA[i:]) + n49, err := m.Spec.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n43 + i += n49 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -4385,44 +4779,44 @@ func (m *UserSpecV2) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x2a i++ i = encodeVarintTypes(dAtA, i, uint64(m.Traits.Size())) - n44, err := m.Traits.MarshalTo(dAtA[i:]) + n50, err := m.Traits.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n44 + i += n50 dAtA[i] = 0x32 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Status.Size())) - n45, err := m.Status.MarshalTo(dAtA[i:]) + n51, err := m.Status.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n45 + i += n51 dAtA[i] = 0x3a i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires))) - n46, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) + n52, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) if err != nil { return 0, err } - i += n46 + i += n52 dAtA[i] = 0x42 i++ i = encodeVarintTypes(dAtA, i, uint64(m.CreatedBy.Size())) - n47, err := m.CreatedBy.MarshalTo(dAtA[i:]) + n53, err := m.CreatedBy.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n47 + i += n53 if m.LocalAuth != nil { dAtA[i] = 0x4a i++ i = encodeVarintTypes(dAtA, i, uint64(m.LocalAuth.Size())) - n48, err := m.LocalAuth.MarshalTo(dAtA[i:]) + n54, err := m.LocalAuth.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n48 + i += n54 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -4497,19 +4891,19 @@ func (m *LoginStatus) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.LockedTime))) - n49, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LockedTime, dAtA[i:]) + n55, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LockedTime, dAtA[i:]) if err != nil { return 0, err } - i += n49 + i += n55 dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.LockExpires))) - n50, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LockExpires, dAtA[i:]) + n56, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LockExpires, dAtA[i:]) if err != nil { return 0, err } - i += n50 + i += n56 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -4535,28 +4929,28 @@ func (m *CreatedBy) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintTypes(dAtA, i, uint64(m.Connector.Size())) - n51, err := m.Connector.MarshalTo(dAtA[i:]) + n57, err := m.Connector.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n51 + i += n57 } dAtA[i] = 0x12 i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Time))) - n52, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) + n58, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) if err != nil { return 0, err } - i += n52 + i += n58 dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(m.User.Size())) - n53, err := m.User.MarshalTo(dAtA[i:]) + n59, err := m.User.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n53 + i += n59 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -4633,11 +5027,11 @@ func (m *LocalAuthSecrets) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(m.U2FRegistration.Size())) - n54, err := m.U2FRegistration.MarshalTo(dAtA[i:]) + n60, err := m.U2FRegistration.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n54 + i += n60 } if m.U2FCounter != 0 { dAtA[i] = 0x20 @@ -4752,19 +5146,19 @@ func (m *ReverseTunnelV2) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) - n55, err := m.Metadata.MarshalTo(dAtA[i:]) + n61, err := m.Metadata.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n55 + i += n61 dAtA[i] = 0x2a i++ i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) - n56, err := m.Spec.MarshalTo(dAtA[i:]) + n62, err := m.Spec.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n56 + i += n62 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -4855,19 +5249,19 @@ func (m *TunnelConnectionV2) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Metadata.Size())) - n57, err := m.Metadata.MarshalTo(dAtA[i:]) + n63, err := m.Metadata.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n57 + i += n63 dAtA[i] = 0x2a i++ i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) - n58, err := m.Spec.MarshalTo(dAtA[i:]) + n64, err := m.Spec.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n58 + i += n64 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -4904,11 +5298,11 @@ func (m *TunnelConnectionSpecV2) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.LastHeartbeat))) - n59, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastHeartbeat, dAtA[i:]) + n65, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastHeartbeat, dAtA[i:]) if err != nil { return 0, err } - i += n59 + i += n65 if len(m.Type) > 0 { dAtA[i] = 0x22 i++ @@ -5517,6 +5911,94 @@ func (m *NamespaceSpec) Size() (n int) { return n } +func (m *ResetPasswordTokenV3) Size() (n int) { + var l int + _ = l + l = len(m.Kind) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.SubKind) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.Spec.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResetPasswordTokenSpecV3) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.URL) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Created) + n += 1 + l + sovTypes(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResetPasswordTokenSecretsV3) Size() (n int) { + var l int + _ = l + l = len(m.Kind) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.SubKind) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovTypes(uint64(l)) + l = m.Spec.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResetPasswordTokenSecretsSpecV3) Size() (n int) { + var l int + _ = l + l = len(m.OTPKey) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.QRCode) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Created) + n += 1 + l + sovTypes(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *AccessRequestV3) Size() (n int) { var l int _ = l @@ -10355,6 +10837,680 @@ func (m *NamespaceSpec) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResetPasswordTokenV3) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResetPasswordTokenV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResetPasswordTokenV3: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubKind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubKind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResetPasswordTokenSpecV3) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResetPasswordTokenSpecV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResetPasswordTokenSpecV3: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field User", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.User = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.URL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Created", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Created, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResetPasswordTokenSecretsV3) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResetPasswordTokenSecretsV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResetPasswordTokenSecretsV3: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubKind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubKind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResetPasswordTokenSecretsSpecV3) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResetPasswordTokenSecretsSpecV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResetPasswordTokenSecretsSpecV3: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OTPKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OTPKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QRCode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.QRCode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Created", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Created, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *AccessRequestV3) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14247,241 +15403,249 @@ var ( ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("types.proto", fileDescriptor_types_c96a02d876242e74) } - -var fileDescriptor_types_c96a02d876242e74 = []byte{ - // 3717 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x3a, 0x4d, 0x73, 0x1c, 0xc7, - 0x75, 0xdc, 0x0f, 0x00, 0xbb, 0x6f, 0x01, 0x10, 0x6c, 0x80, 0xe4, 0xf2, 0x43, 0x1c, 0x68, 0x14, - 0xc9, 0x94, 0x43, 0x03, 0x31, 0x18, 0x29, 0x96, 0x62, 0x46, 0xc2, 0x62, 0x01, 0x12, 0x06, 0x48, - 0x42, 0x03, 0x10, 0x2e, 0x57, 0x3e, 0x26, 0x83, 0x99, 0xc6, 0x62, 0x0a, 0xb3, 0x33, 0x9b, 0x99, - 0x1e, 0x90, 0x7b, 0x73, 0x25, 0xa9, 0x4a, 0x25, 0xae, 0xb2, 0x93, 0x4a, 0xb9, 0xa2, 0xaa, 0xe4, - 0x90, 0x6b, 0x0e, 0xc9, 0x35, 0xa7, 0x1c, 0x52, 0xe5, 0x03, 0x8f, 0x3e, 0xbb, 0x9c, 0x71, 0xa2, - 0x1c, 0x5c, 0xb5, 0x3f, 0x41, 0x97, 0xa4, 0xfa, 0x75, 0xcf, 0x4c, 0xcf, 0xee, 0x82, 0x58, 0xc9, - 0xba, 0x50, 0xa7, 0x9d, 0x7d, 0x5f, 0xdd, 0xef, 0xf5, 0xeb, 0xf7, 0x5e, 0xbf, 0x6e, 0x68, 0xb0, - 0x7e, 0x8f, 0x46, 0x2b, 0xbd, 0x30, 0x60, 0x01, 0xa9, 0x45, 0x34, 0x3c, 0x73, 0x6d, 0x1a, 0xdd, - 0x5c, 0xea, 0x04, 0x9d, 0x00, 0x81, 0xab, 0xfc, 0x4b, 0xe0, 0x6f, 0x6a, 0x9d, 0x20, 0xe8, 0x78, - 0x74, 0x15, 0xff, 0x1d, 0xc5, 0xc7, 0xab, 0xcc, 0xed, 0xd2, 0x88, 0x59, 0xdd, 0x9e, 0x24, 0x78, - 0xd0, 0x71, 0xd9, 0x49, 0x7c, 0xb4, 0x62, 0x07, 0xdd, 0xd5, 0x4e, 0x68, 0x9d, 0xb9, 0xcc, 0x62, - 0x6e, 0xe0, 0x5b, 0xde, 0x2a, 0xa3, 0x1e, 0xed, 0x05, 0x21, 0x5b, 0xf5, 0xdc, 0xa3, 0xd5, 0xe7, - 0xa1, 0xd5, 0xeb, 0xd1, 0x30, 0xca, 0x3e, 0x04, 0xbb, 0xfe, 0xcb, 0x12, 0xd4, 0x77, 0x28, 0xed, - 0xad, 0x7b, 0xee, 0x19, 0x25, 0xab, 0x00, 0xfb, 0x34, 0x3c, 0xa3, 0xe1, 0x13, 0xab, 0x4b, 0x9b, - 0xa5, 0xe5, 0xd2, 0xdd, 0x7a, 0xeb, 0xf2, 0x20, 0xd1, 0x1a, 0x11, 0x42, 0x4d, 0xdf, 0xea, 0x52, - 0x43, 0x21, 0x21, 0xbf, 0x0d, 0x75, 0xfe, 0x1b, 0xf5, 0x2c, 0x9b, 0x36, 0xcb, 0x48, 0x3f, 0x37, - 0x48, 0xb4, 0xba, 0x9f, 0x02, 0x8d, 0x1c, 0x4f, 0xde, 0x81, 0x99, 0x5d, 0x6a, 0x45, 0x74, 0xbb, - 0xdd, 0xac, 0x2c, 0x97, 0xee, 0x56, 0x5a, 0xb3, 0x83, 0x44, 0xab, 0x79, 0x1c, 0x64, 0xba, 0x8e, - 0x91, 0x22, 0xc9, 0x36, 0xcc, 0x6c, 0xbe, 0xe8, 0xb9, 0x21, 0x8d, 0x9a, 0xd5, 0xe5, 0xd2, 0xdd, - 0xc6, 0xda, 0xcd, 0x15, 0x61, 0x85, 0x95, 0xd4, 0x0a, 0x2b, 0x07, 0xa9, 0x15, 0x5a, 0x8b, 0x2f, - 0x13, 0xed, 0xd2, 0x20, 0xd1, 0x66, 0xa8, 0x60, 0xf9, 0xdb, 0x5f, 0x69, 0x25, 0x23, 0xe5, 0xd7, - 0xff, 0xa6, 0x02, 0xb5, 0xc7, 0x94, 0x59, 0x8e, 0xc5, 0x2c, 0x72, 0x1b, 0xaa, 0x8a, 0x5e, 0xb5, - 0x41, 0xa2, 0x55, 0x51, 0x21, 0x84, 0x92, 0xb7, 0x46, 0x55, 0x99, 0x1a, 0x24, 0x5a, 0xe9, 0x5b, - 0xaa, 0x0a, 0xbf, 0x0f, 0x8d, 0x36, 0x8d, 0xec, 0xd0, 0xed, 0x71, 0x23, 0xa3, 0x1a, 0xf5, 0xd6, - 0x8d, 0x41, 0xa2, 0x5d, 0x75, 0x72, 0xf0, 0xbd, 0xa0, 0xeb, 0x32, 0xda, 0xed, 0xb1, 0xbe, 0xa1, - 0x52, 0x93, 0x5d, 0x98, 0xde, 0xb5, 0x8e, 0xa8, 0x17, 0x35, 0xa7, 0x96, 0x2b, 0x77, 0x1b, 0x6b, - 0x77, 0x56, 0xd2, 0xc5, 0x5f, 0x49, 0xe7, 0xb8, 0x22, 0x08, 0x36, 0x7d, 0x16, 0xf6, 0x5b, 0x4b, - 0x83, 0x44, 0x5b, 0xf0, 0x10, 0xa0, 0x88, 0x94, 0x32, 0xc8, 0x7e, 0x6e, 0xa5, 0xe9, 0x0b, 0xad, - 0xf4, 0xc6, 0xcb, 0x44, 0x2b, 0x0d, 0x12, 0xed, 0x8a, 0xb4, 0x52, 0x2e, 0xaf, 0x60, 0x2f, 0xb2, - 0x0c, 0xe5, 0xed, 0x76, 0x73, 0x06, 0x57, 0x67, 0x61, 0x90, 0x68, 0xb3, 0xae, 0xa3, 0x0c, 0x5d, - 0xde, 0x6e, 0xdf, 0xfc, 0x00, 0x1a, 0xca, 0x1c, 0xc9, 0x02, 0x54, 0x4e, 0x69, 0x5f, 0x98, 0xd4, - 0xe0, 0x9f, 0x64, 0x09, 0xa6, 0xce, 0x2c, 0x2f, 0x96, 0x36, 0x34, 0xc4, 0x9f, 0x0f, 0xcb, 0xdf, - 0x29, 0xe9, 0x3f, 0xad, 0x42, 0xcd, 0x08, 0x84, 0x7f, 0x92, 0x77, 0x61, 0x6a, 0x9f, 0x59, 0x2c, - 0x5d, 0x8d, 0xc5, 0x41, 0xa2, 0x5d, 0x8e, 0x38, 0x40, 0x19, 0x4f, 0x50, 0x70, 0xd2, 0xbd, 0x13, - 0x2b, 0x4a, 0x57, 0x05, 0x49, 0x7b, 0x1c, 0xa0, 0x92, 0x22, 0x05, 0x79, 0x07, 0xaa, 0x8f, 0x03, - 0x87, 0xca, 0x85, 0x21, 0x83, 0x44, 0x9b, 0xef, 0x06, 0x8e, 0x4a, 0x88, 0x78, 0x72, 0x0f, 0xea, - 0x1b, 0x71, 0x18, 0x52, 0x9f, 0x6d, 0xb7, 0xd1, 0xc9, 0xea, 0xad, 0xf9, 0x41, 0xa2, 0x81, 0x2d, - 0x80, 0xdc, 0x1d, 0x73, 0x02, 0x6e, 0xea, 0x7d, 0x66, 0x85, 0x8c, 0x3a, 0xcd, 0xa9, 0x89, 0x4c, - 0xcd, 0x1d, 0xf2, 0x4a, 0x24, 0x58, 0x86, 0x4d, 0x2d, 0x25, 0x91, 0x47, 0xd0, 0x78, 0x18, 0x5a, - 0x36, 0xdd, 0xa3, 0xa1, 0x1b, 0x38, 0xb8, 0x86, 0x95, 0xd6, 0x3b, 0x83, 0x44, 0xbb, 0xd6, 0xe1, - 0x60, 0xb3, 0x87, 0xf0, 0x9c, 0xfb, 0xf3, 0x44, 0xab, 0xb5, 0xe3, 0x10, 0xad, 0x67, 0xa8, 0xac, - 0xe4, 0x4f, 0xf9, 0x92, 0x44, 0x0c, 0x4d, 0x4b, 0x1d, 0x5c, 0xbd, 0x57, 0x4f, 0x51, 0x97, 0x53, - 0xbc, 0xe6, 0x59, 0x11, 0x33, 0x43, 0xc1, 0x37, 0x34, 0x4f, 0x55, 0x24, 0x31, 0xa0, 0xb6, 0x6f, - 0x9f, 0x50, 0x27, 0xf6, 0x68, 0xb3, 0x26, 0xc5, 0x67, 0xbe, 0x9b, 0x2e, 0x69, 0x4a, 0xd1, 0xba, - 0x29, 0xc5, 0x93, 0x48, 0x42, 0x14, 0xf3, 0x67, 0x72, 0x3e, 0xac, 0x7d, 0xfa, 0xcf, 0xda, 0xa5, - 0x1f, 0xfe, 0x72, 0xf9, 0x92, 0xfe, 0xef, 0x65, 0x58, 0x18, 0x16, 0x42, 0x8e, 0x61, 0xee, 0x59, - 0xcf, 0xb1, 0x18, 0xdd, 0xf0, 0x5c, 0xea, 0xb3, 0x08, 0xfd, 0xe4, 0xd5, 0x6a, 0xfd, 0x96, 0x1c, - 0xb7, 0x19, 0x23, 0xa3, 0x69, 0x0b, 0xce, 0x21, 0xc5, 0x8a, 0x62, 0xf3, 0x71, 0x44, 0x54, 0x8b, - 0xd0, 0xc9, 0xbe, 0xd8, 0x38, 0x22, 0x38, 0x9e, 0x33, 0x8e, 0x14, 0x2b, 0x7d, 0xc8, 0x77, 0x8e, - 0xfa, 0xe8, 0x9c, 0x93, 0xfb, 0x10, 0x67, 0x19, 0xe3, 0x43, 0x1c, 0xac, 0xff, 0xba, 0x04, 0xf3, - 0x06, 0x8d, 0x82, 0x38, 0xb4, 0xe9, 0x23, 0x6a, 0x39, 0x34, 0xe4, 0x3b, 0x60, 0xc7, 0xf5, 0x1d, - 0xb9, 0xad, 0x70, 0x07, 0x9c, 0xba, 0xbe, 0xba, 0x8b, 0x11, 0x4f, 0x7e, 0x07, 0x66, 0xf6, 0xe3, - 0x23, 0x24, 0x15, 0xdb, 0xea, 0x1a, 0xae, 0x58, 0x7c, 0x64, 0x0e, 0x91, 0xa7, 0x64, 0x64, 0x15, - 0x66, 0x0e, 0x69, 0x18, 0xe5, 0x71, 0xef, 0x2a, 0x9f, 0xe1, 0x99, 0x00, 0xa9, 0x0c, 0x92, 0x8a, - 0x7c, 0x2f, 0x8f, 0xbd, 0x32, 0x90, 0x93, 0xd1, 0x88, 0x97, 0x7b, 0x4b, 0x57, 0x42, 0x54, 0x6f, - 0x49, 0xa9, 0xf4, 0xbf, 0x2a, 0x43, 0x4d, 0x98, 0xf2, 0x70, 0x8d, 0x07, 0x72, 0x45, 0x47, 0x0c, - 0xe4, 0x7c, 0xd2, 0x5f, 0x5a, 0xb3, 0xb7, 0x87, 0x35, 0x6b, 0xf0, 0x84, 0x22, 0x35, 0xcb, 0xf5, - 0xf9, 0x78, 0x22, 0x7d, 0x16, 0xa4, 0x3e, 0xb5, 0x54, 0x9f, 0x5c, 0x0b, 0xf2, 0x1d, 0xa8, 0xee, - 0xf7, 0xa8, 0x2d, 0xa3, 0xc8, 0xb5, 0x9c, 0x5b, 0xa8, 0xc6, 0x71, 0x87, 0x6b, 0xad, 0x59, 0x29, - 0xa1, 0x1a, 0xf5, 0xa8, 0x6d, 0x20, 0x87, 0xb2, 0x5b, 0x7e, 0x5e, 0x81, 0x59, 0x95, 0x9c, 0x5b, - 0x63, 0xdd, 0x71, 0x42, 0xd5, 0x1a, 0x96, 0xe3, 0x84, 0x06, 0x42, 0xc9, 0x07, 0x00, 0x7b, 0xf1, - 0x91, 0xe7, 0xda, 0x48, 0x53, 0xce, 0x13, 0x56, 0x0f, 0xa1, 0x26, 0x27, 0x55, 0x6c, 0xa2, 0x10, - 0x93, 0xbb, 0x50, 0x7b, 0x14, 0x44, 0x8c, 0xe7, 0x48, 0x69, 0x17, 0x4c, 0xd8, 0x27, 0x12, 0x66, - 0x64, 0x58, 0x62, 0x41, 0x7d, 0xa3, 0xeb, 0xc8, 0xe4, 0x56, 0xc5, 0xe4, 0xf6, 0xf6, 0x78, 0xe5, - 0x56, 0x32, 0x3a, 0x91, 0xe3, 0x6e, 0x4b, 0x5d, 0x97, 0xec, 0xae, 0x63, 0x8e, 0xe4, 0xba, 0x5c, - 0x2a, 0x77, 0xa6, 0x34, 0x46, 0x48, 0xf3, 0x91, 0xd1, 0x10, 0x94, 0x3b, 0x53, 0x28, 0x21, 0xaa, - 0x33, 0x65, 0xb9, 0xe7, 0x7d, 0xa8, 0x3f, 0x8b, 0xe8, 0x41, 0xec, 0xfb, 0xd4, 0xc3, 0xc0, 0x5b, - 0x6b, 0x35, 0xf9, 0x1c, 0xe2, 0x88, 0x9a, 0x0c, 0xa1, 0xea, 0x1c, 0x32, 0xd2, 0x9b, 0x87, 0x30, - 0x5f, 0x9c, 0xfe, 0x98, 0xf4, 0xb7, 0xa2, 0xa6, 0xbf, 0xc6, 0x5a, 0x33, 0x9f, 0xe4, 0x46, 0xd0, - 0xed, 0x5a, 0xbe, 0x60, 0x3f, 0x5c, 0x53, 0x13, 0xe3, 0x8f, 0x4a, 0x30, 0x5f, 0xc4, 0x92, 0x15, - 0x98, 0x96, 0x89, 0xa1, 0x84, 0x89, 0x81, 0xfb, 0xf0, 0xb4, 0x48, 0x09, 0x85, 0x44, 0x20, 0xa9, - 0xb8, 0x0b, 0x4b, 0x09, 0xcd, 0xf2, 0x72, 0x25, 0x75, 0x61, 0x5b, 0x80, 0x8c, 0x14, 0x47, 0x74, - 0x98, 0x36, 0x68, 0x14, 0x7b, 0x4c, 0x2e, 0x28, 0x70, 0xb1, 0x21, 0x42, 0x0c, 0x89, 0xd1, 0x7f, - 0x00, 0x70, 0xb0, 0xbb, 0xbf, 0x43, 0xfb, 0x7b, 0x96, 0x8b, 0xf1, 0x64, 0x83, 0x86, 0x0c, 0xa7, - 0x31, 0x2b, 0xe2, 0x89, 0x4d, 0x43, 0xa6, 0xc6, 0x13, 0x8e, 0x27, 0x6f, 0x41, 0x65, 0x87, 0xf6, - 0x51, 0xeb, 0xd9, 0xd6, 0x95, 0x41, 0xa2, 0xcd, 0x9d, 0x52, 0x25, 0x6e, 0x19, 0x1c, 0xab, 0xff, - 0xb4, 0x0c, 0x97, 0x39, 0xf5, 0x7a, 0xcc, 0x4e, 0x82, 0xd0, 0x65, 0xfd, 0xd7, 0x79, 0x33, 0x7f, - 0x54, 0xd8, 0xcc, 0x6f, 0x28, 0x0b, 0xad, 0x6a, 0x38, 0xd1, 0x9e, 0xfe, 0xeb, 0x2a, 0x2c, 0x8e, - 0xe1, 0x22, 0xf7, 0xa0, 0x7a, 0xd0, 0xef, 0xa5, 0x35, 0x12, 0xf7, 0xd1, 0x2a, 0x3f, 0x3c, 0x7c, - 0x9e, 0x68, 0xb3, 0x29, 0x39, 0xc7, 0x1b, 0x48, 0x45, 0xd6, 0xa0, 0xb1, 0xe1, 0xc5, 0x11, 0x93, - 0xe5, 0xbb, 0xb0, 0x17, 0x56, 0x71, 0xb6, 0x00, 0x8b, 0xfa, 0x5d, 0x25, 0x22, 0xef, 0xc1, 0xec, - 0xc6, 0x09, 0xb5, 0x4f, 0x5d, 0xbf, 0xb3, 0x43, 0xfb, 0x51, 0xb3, 0xb2, 0x5c, 0x49, 0xd7, 0xcf, - 0x96, 0x70, 0xf3, 0x94, 0xf6, 0x23, 0xa3, 0x40, 0x46, 0xbe, 0x0b, 0x8d, 0x7d, 0xb7, 0xe3, 0xa7, - 0x5c, 0x55, 0xe4, 0xba, 0xc9, 0x4b, 0x8a, 0x48, 0x80, 0x91, 0x49, 0x2d, 0x84, 0x15, 0x72, 0x5e, - 0xd0, 0x19, 0x81, 0x47, 0x45, 0x1d, 0x2c, 0x0b, 0xba, 0x90, 0x03, 0xd4, 0x82, 0x0e, 0x29, 0xc8, - 0x0e, 0xcc, 0xf0, 0x8f, 0xc7, 0x56, 0xaf, 0x39, 0x8d, 0x71, 0xe5, 0xaa, 0xba, 0xeb, 0x11, 0xd1, - 0x73, 0xfd, 0x8e, 0xba, 0xf1, 0x3d, 0x6a, 0x76, 0xad, 0x9e, 0xea, 0x1a, 0x92, 0x90, 0x7c, 0x1f, - 0x1a, 0xb9, 0x67, 0x47, 0xcd, 0x19, 0x14, 0xb8, 0x94, 0x0b, 0xcc, 0x91, 0x2d, 0x4d, 0xca, 0xbb, - 0xce, 0xbc, 0x88, 0xeb, 0x62, 0xf6, 0x38, 0x8b, 0xaa, 0x90, 0x22, 0xa9, 0x10, 0x9c, 0x6a, 0xaf, - 0x0c, 0x4e, 0xa5, 0x8b, 0x82, 0x93, 0x6e, 0x40, 0x43, 0x51, 0x4c, 0xec, 0xd8, 0x6e, 0x90, 0x15, - 0xca, 0x72, 0xc7, 0x72, 0x88, 0x21, 0x31, 0x44, 0x83, 0xa9, 0xdd, 0xc0, 0xb6, 0x3c, 0xb9, 0xf5, - 0xeb, 0x83, 0x44, 0x9b, 0xf2, 0x38, 0xc0, 0x10, 0x70, 0xfd, 0xbf, 0x4a, 0xb0, 0xb0, 0x17, 0x06, - 0x67, 0x2e, 0x77, 0xfd, 0x83, 0xe0, 0x94, 0xfa, 0x87, 0xdf, 0x26, 0xdb, 0xe9, 0x2a, 0x94, 0x90, - 0xeb, 0x3e, 0xe7, 0xc2, 0x55, 0xf8, 0x3c, 0xd1, 0xde, 0xb9, 0xf0, 0x54, 0x89, 0xd6, 0x4f, 0x57, - 0x49, 0x39, 0x8b, 0x94, 0x27, 0x2f, 0x6e, 0x2e, 0x38, 0x8b, 0x68, 0x30, 0x85, 0x53, 0x95, 0xdb, - 0x18, 0xb5, 0x62, 0x1c, 0x60, 0x08, 0xb8, 0xb2, 0x7f, 0xfe, 0xa1, 0x3c, 0xa2, 0xdf, 0x6b, 0x1c, - 0x58, 0x3e, 0x2e, 0x04, 0x16, 0xe5, 0x94, 0x58, 0x54, 0x71, 0xa2, 0xc8, 0x62, 0xc1, 0xd2, 0x38, - 0xae, 0xaf, 0x70, 0xf1, 0xf5, 0xbf, 0x2f, 0xc3, 0x3c, 0x3f, 0xa8, 0xb9, 0x36, 0x0e, 0x10, 0xbd, - 0xce, 0xa6, 0xff, 0x83, 0x82, 0xe9, 0x6f, 0x2b, 0x35, 0x8c, 0xa2, 0xe0, 0x44, 0x86, 0x3f, 0x05, - 0x32, 0xca, 0x43, 0x9e, 0xc1, 0xac, 0x0a, 0x45, 0xeb, 0x17, 0x0e, 0x53, 0xc3, 0xbb, 0xb4, 0x75, - 0x55, 0x8e, 0x32, 0x17, 0x21, 0x9f, 0x89, 0x3b, 0x20, 0x32, 0x0a, 0x62, 0xf4, 0xbf, 0x2b, 0xc3, - 0x9c, 0x12, 0xd5, 0x5f, 0xe7, 0x15, 0x78, 0x50, 0x58, 0x81, 0x5b, 0x4a, 0x56, 0xcd, 0xf5, 0x9b, - 0x68, 0x01, 0x1e, 0xc2, 0x95, 0x11, 0x96, 0xe1, 0x14, 0x59, 0x9a, 0x20, 0x45, 0x8a, 0xa2, 0x45, - 0xfc, 0xdf, 0x08, 0xfc, 0x63, 0xb7, 0x73, 0x78, 0xff, 0xeb, 0x58, 0xb4, 0xa8, 0x1a, 0xa2, 0xb5, - 0xee, 0x5f, 0x60, 0xe0, 0x9f, 0x4c, 0xc1, 0xe2, 0x18, 0x2e, 0xb2, 0x0e, 0x0b, 0xfb, 0x34, 0xc2, - 0x89, 0x53, 0x3b, 0x08, 0x1d, 0xd7, 0xef, 0x48, 0x3b, 0xe1, 0x81, 0x31, 0x12, 0x38, 0x33, 0x4c, - 0x91, 0xc6, 0x08, 0x39, 0xb6, 0x67, 0x84, 0xe4, 0xed, 0xb6, 0x34, 0xa1, 0x68, 0xcf, 0xc8, 0x45, - 0xc2, 0xf6, 0x4c, 0x4a, 0x40, 0x76, 0x61, 0x71, 0x2f, 0x0c, 0x5e, 0xf4, 0xb1, 0x42, 0x89, 0xf8, - 0xa1, 0x44, 0x96, 0x32, 0x9c, 0x0f, 0x8b, 0x92, 0x1e, 0x47, 0x9b, 0x58, 0xd0, 0x44, 0x26, 0x3f, - 0xbf, 0x88, 0x9a, 0x66, 0x1c, 0x1b, 0xf9, 0x10, 0xa6, 0xd6, 0x63, 0xc7, 0x65, 0xd2, 0xc0, 0x4a, - 0xbd, 0x81, 0x60, 0xa1, 0x6a, 0x6b, 0x4e, 0x9a, 0x66, 0xca, 0xe2, 0x40, 0x43, 0xb0, 0x90, 0x4f, - 0xb8, 0xcf, 0xb9, 0xd4, 0x67, 0xdb, 0x8e, 0x47, 0x79, 0xc6, 0x0b, 0x62, 0x86, 0xa6, 0xae, 0xb4, - 0xde, 0x1a, 0x24, 0xda, 0xa2, 0xe8, 0x48, 0x98, 0xae, 0xe3, 0x51, 0x93, 0x09, 0x74, 0xa1, 0x9a, - 0x1f, 0xe5, 0x26, 0x3f, 0x80, 0xab, 0x6d, 0x37, 0xb2, 0x03, 0xdf, 0xa7, 0x36, 0x13, 0xa9, 0xd1, - 0xc1, 0x82, 0x5c, 0x9c, 0x5b, 0xb8, 0xd8, 0xeb, 0x4e, 0x46, 0x60, 0x8a, 0x9c, 0xea, 0x98, 0xbc, - 0x46, 0xff, 0x3c, 0xd1, 0xaa, 0xad, 0x20, 0xf0, 0x8c, 0xf1, 0x12, 0xf8, 0x6c, 0xb3, 0xd6, 0xef, - 0xb6, 0xcf, 0x68, 0x78, 0x66, 0x79, 0xb2, 0xf7, 0x87, 0xb3, 0x3d, 0xa5, 0xb4, 0x67, 0x5a, 0x1c, - 0x6b, 0xba, 0x12, 0x5d, 0x9c, 0xed, 0x08, 0x37, 0xd9, 0x52, 0x44, 0x6e, 0x04, 0xb1, 0xcf, 0x1e, - 0x5b, 0x2f, 0xb0, 0x22, 0xaa, 0x88, 0x13, 0x96, 0x22, 0xd2, 0xe6, 0x68, 0xb3, 0x6b, 0xbd, 0x30, - 0x46, 0x59, 0xc8, 0xef, 0x42, 0x1d, 0x2b, 0x17, 0x5e, 0xe1, 0x36, 0xeb, 0xa8, 0x29, 0xdf, 0x43, - 0x80, 0x55, 0x8d, 0x69, 0xc5, 0xec, 0x24, 0x53, 0x2e, 0x27, 0xd4, 0x3f, 0xad, 0x40, 0x43, 0x59, - 0x24, 0x7e, 0x76, 0x51, 0xca, 0x67, 0x3c, 0xbb, 0xf0, 0xf2, 0x59, 0x3d, 0xbb, 0x60, 0xe1, 0x7c, - 0x8f, 0xd7, 0x58, 0x1d, 0xbe, 0xf9, 0x84, 0xaf, 0x61, 0xe3, 0x35, 0x44, 0x88, 0xda, 0x78, 0x15, - 0x34, 0x64, 0x17, 0x16, 0x70, 0x10, 0xe9, 0xb5, 0xd1, 0x33, 0x63, 0x5b, 0xfa, 0xda, 0xf2, 0x20, - 0xd1, 0x6e, 0xa3, 0x43, 0x98, 0xd2, 0xcb, 0x23, 0x33, 0x0e, 0x5d, 0x45, 0xc6, 0x08, 0x27, 0xf9, - 0xa7, 0x12, 0xcc, 0x23, 0x70, 0xf3, 0x8c, 0xfa, 0x0c, 0x85, 0x55, 0x65, 0x77, 0x20, 0x6b, 0xd5, - 0xef, 0xb3, 0xd0, 0xf5, 0x3b, 0x87, 0xfc, 0xbc, 0x18, 0xb5, 0xfe, 0x88, 0x7b, 0xde, 0x2f, 0x12, - 0xed, 0xfd, 0x2f, 0xd6, 0xf8, 0x97, 0x42, 0xa2, 0x41, 0xa2, 0xdd, 0x14, 0x53, 0xa4, 0x38, 0xe0, - 0xd0, 0x04, 0x87, 0xe6, 0x42, 0xb6, 0xe4, 0xec, 0x0e, 0xac, 0x23, 0x8f, 0x62, 0xcc, 0x9c, 0x42, - 0x55, 0xef, 0xe4, 0x72, 0x18, 0x47, 0x61, 0xdc, 0x1c, 0x91, 0x93, 0x71, 0xe9, 0xff, 0x57, 0x52, - 0xda, 0xeb, 0xaf, 0x6f, 0xf8, 0xfc, 0xa0, 0x10, 0x3e, 0xaf, 0xe7, 0xdc, 0x99, 0x6e, 0x1c, 0x3d, - 0x2e, 0x70, 0xea, 0x97, 0x61, 0xae, 0x40, 0x84, 0x79, 0x65, 0xdd, 0xb6, 0x69, 0x14, 0x19, 0xf4, - 0xcf, 0x62, 0x1a, 0xb1, 0xaf, 0x65, 0x5e, 0x29, 0x68, 0x38, 0x51, 0x5e, 0xf9, 0xcf, 0x32, 0x2c, - 0x8e, 0xe1, 0xe2, 0xb6, 0x79, 0x16, 0xd1, 0x42, 0x9f, 0x2b, 0x8e, 0x68, 0x68, 0x20, 0x94, 0x9f, - 0x16, 0x44, 0x41, 0xab, 0x9c, 0x81, 0xb0, 0xa0, 0x4d, 0xcf, 0x28, 0xeb, 0xe9, 0x85, 0x03, 0x37, - 0xc4, 0xbc, 0xda, 0x7c, 0x4b, 0x87, 0xe1, 0xd8, 0x57, 0x5e, 0x44, 0xec, 0xc3, 0xcc, 0x46, 0x48, - 0xb1, 0xc9, 0x5e, 0x9d, 0xfc, 0x98, 0x63, 0x0b, 0x96, 0xe1, 0x63, 0x8e, 0x94, 0xa4, 0x9e, 0x9d, - 0xa6, 0xbe, 0xaa, 0xb3, 0x93, 0xfe, 0x97, 0xa5, 0x21, 0x1b, 0x6e, 0xb9, 0x1e, 0xa3, 0x21, 0xb9, - 0x86, 0xf7, 0x3b, 0xc2, 0x82, 0xd3, 0x83, 0x44, 0x2b, 0xbb, 0x8e, 0x51, 0xde, 0x6e, 0x67, 0xb6, - 0x2d, 0x8f, 0xb5, 0xed, 0xef, 0x4d, 0x66, 0x3a, 0xb4, 0x39, 0x9a, 0x4e, 0x1a, 0x4c, 0xff, 0x8b, - 0x32, 0x4c, 0x73, 0xeb, 0xbf, 0xce, 0x9e, 0xfd, 0x7e, 0xc1, 0xb3, 0x97, 0x8a, 0xed, 0x87, 0x89, - 0x1c, 0xfa, 0xd7, 0x25, 0x80, 0x9c, 0x98, 0x7c, 0x0f, 0x66, 0x9e, 0xe2, 0x85, 0x60, 0x7a, 0xa7, - 0x31, 0xd4, 0xd2, 0x90, 0xc8, 0xd6, 0x8d, 0x74, 0xad, 0x03, 0x01, 0x50, 0xad, 0x20, 0x69, 0xc8, - 0x43, 0x98, 0x5a, 0xf7, 0xbc, 0xe0, 0xf9, 0x68, 0xb7, 0x91, 0x4b, 0xda, 0x08, 0x7c, 0xc7, 0x15, - 0xc2, 0xae, 0x4b, 0x61, 0x97, 0x2d, 0x4e, 0xae, 0xba, 0x36, 0xf2, 0x93, 0x36, 0x54, 0xdb, 0xd4, - 0x4f, 0xef, 0x26, 0xce, 0x97, 0x73, 0x4d, 0xca, 0x99, 0x77, 0xa8, 0xaf, 0xb6, 0xf7, 0x90, 0x5b, - 0xff, 0x59, 0x55, 0x34, 0x2f, 0xd2, 0xe9, 0x3d, 0x80, 0xd9, 0xad, 0x20, 0x7c, 0x6e, 0x85, 0xce, - 0x7a, 0x87, 0xfa, 0xa2, 0x89, 0x58, 0xc3, 0xf6, 0xf3, 0xdc, 0xb1, 0x80, 0x9b, 0x16, 0x47, 0x64, - 0xc9, 0xbc, 0x40, 0x4e, 0x9e, 0xc2, 0xdc, 0x63, 0xeb, 0x85, 0xcc, 0x96, 0x07, 0x07, 0xbb, 0xa8, - 0x65, 0xa5, 0xf5, 0xee, 0x20, 0xd1, 0x6e, 0x74, 0xad, 0x17, 0x69, 0x92, 0x35, 0x19, 0xf3, 0xce, - 0xb9, 0x27, 0x2b, 0xf2, 0x13, 0x0f, 0xe6, 0xf7, 0x82, 0x90, 0xc9, 0x41, 0x78, 0x61, 0x2a, 0xf4, - 0x5d, 0xcc, 0xf5, 0xe5, 0xd3, 0xc0, 0x4c, 0xdb, 0x5a, 0x7d, 0x99, 0x68, 0xa5, 0x5f, 0x24, 0x1a, - 0x70, 0x90, 0xd0, 0x88, 0x0f, 0xcc, 0x33, 0xab, 0x79, 0x9c, 0x49, 0x50, 0x73, 0x5e, 0x51, 0x36, - 0x79, 0x00, 0x57, 0x78, 0x9d, 0xe5, 0x1e, 0xbb, 0xb6, 0xc5, 0xe8, 0x56, 0x10, 0x76, 0x2d, 0x26, - 0x2f, 0x1b, 0xf1, 0x52, 0x9d, 0xd7, 0x68, 0x5c, 0x52, 0xd7, 0x62, 0xc6, 0x28, 0x25, 0xf9, 0xc3, - 0xf3, 0x8b, 0xc9, 0x6f, 0x0d, 0x12, 0xed, 0x8d, 0x31, 0xc5, 0xe4, 0x39, 0x56, 0x18, 0x53, 0x56, - 0x76, 0x5e, 0x5d, 0x56, 0x7e, 0x5b, 0xb6, 0xaa, 0xde, 0x3c, 0xa7, 0xb4, 0x2c, 0x0c, 0xf4, 0xca, - 0x22, 0x73, 0x0d, 0x2a, 0xad, 0xbd, 0x2d, 0xec, 0xb5, 0xc9, 0x02, 0x89, 0xfa, 0x27, 0x96, 0x6f, - 0x53, 0x27, 0x3f, 0x01, 0xa8, 0x6d, 0xe2, 0xd6, 0xde, 0x96, 0xfe, 0x93, 0x0a, 0xcc, 0x17, 0xfd, - 0x8e, 0xe8, 0x30, 0xbd, 0x1b, 0x74, 0x5c, 0x3f, 0x6d, 0x58, 0x60, 0x1b, 0xcc, 0x43, 0x88, 0x21, - 0x31, 0xe4, 0x6d, 0x80, 0x2c, 0xc3, 0xa6, 0x79, 0x40, 0x5e, 0xe1, 0x2b, 0x08, 0xf2, 0x27, 0x00, - 0x4f, 0x02, 0x87, 0xca, 0xdb, 0x8a, 0x8a, 0xdc, 0x82, 0x59, 0x9d, 0x24, 0x3a, 0xf0, 0xa2, 0xd6, - 0xfa, 0x86, 0xac, 0xb5, 0xe4, 0x9d, 0xfb, 0x20, 0xd1, 0xae, 0xfa, 0x81, 0x43, 0x47, 0x2f, 0x2a, - 0x14, 0x89, 0xe4, 0x01, 0x4c, 0x19, 0xb1, 0x47, 0xd3, 0x8b, 0x90, 0x79, 0x65, 0x2f, 0xc5, 0x1e, - 0xcd, 0x77, 0x62, 0x18, 0x0f, 0x77, 0x3c, 0x39, 0x80, 0x7c, 0x04, 0xb0, 0x13, 0x1f, 0xd1, 0x87, - 0x61, 0x10, 0xf7, 0xd2, 0x0e, 0xa9, 0x36, 0x48, 0xb4, 0x5b, 0xa7, 0xf1, 0x11, 0x0d, 0x7d, 0xca, - 0x68, 0x64, 0x76, 0x10, 0xa9, 0x8e, 0x9f, 0xb3, 0x10, 0x03, 0x66, 0x64, 0x58, 0x96, 0x0f, 0x03, - 0xde, 0x3c, 0x27, 0x1b, 0x2b, 0xdb, 0x1a, 0x4f, 0x66, 0xa1, 0x00, 0x17, 0x3a, 0xa7, 0x02, 0xa4, - 0xb7, 0xe1, 0xfa, 0x39, 0xac, 0x79, 0x33, 0xb7, 0x74, 0x51, 0x33, 0x57, 0xff, 0x59, 0x09, 0xaa, - 0x5c, 0x49, 0xf2, 0x1e, 0xd4, 0xd3, 0x6b, 0xcb, 0x94, 0xef, 0x3a, 0x3f, 0x71, 0x84, 0x29, 0x50, - 0xbd, 0x7f, 0xc9, 0x28, 0xf9, 0x50, 0x87, 0x34, 0x3c, 0x4a, 0xd7, 0x16, 0x87, 0x3a, 0xe3, 0x00, - 0x75, 0x28, 0xa4, 0xe0, 0xa4, 0xdf, 0x3f, 0xa1, 0x61, 0x7a, 0x71, 0x85, 0xa4, 0xcf, 0x39, 0x40, - 0x25, 0x45, 0x0a, 0xb2, 0x0a, 0x33, 0xeb, 0xb6, 0x88, 0xc7, 0x55, 0x94, 0x8b, 0xc6, 0xb0, 0xec, - 0x91, 0xa0, 0x2b, 0xa9, 0xf4, 0x37, 0xa1, 0x9e, 0x45, 0x09, 0xb2, 0x04, 0x53, 0xf8, 0x21, 0x62, - 0x9b, 0x21, 0xfe, 0x60, 0xe2, 0xe3, 0xa9, 0xf3, 0x75, 0xee, 0xc4, 0x9c, 0x9b, 0xf8, 0xb8, 0x62, - 0x13, 0xb5, 0x60, 0xfe, 0x6d, 0x1a, 0x20, 0x27, 0x26, 0x14, 0xe6, 0x9f, 0x6e, 0xb7, 0x37, 0xb6, - 0x1d, 0xea, 0x33, 0x97, 0xb9, 0x74, 0x4c, 0xfb, 0x6b, 0xf3, 0x05, 0xa3, 0xa1, 0x6f, 0x79, 0x92, - 0xa6, 0xdf, 0x7a, 0x53, 0x0e, 0x70, 0x23, 0x70, 0x1d, 0xdb, 0x74, 0x33, 0x56, 0x35, 0xec, 0x16, - 0x85, 0xf2, 0x61, 0xf6, 0xd7, 0x1f, 0xef, 0x2a, 0xc3, 0x94, 0x27, 0x1f, 0x26, 0xb2, 0xba, 0xde, - 0x39, 0xc3, 0x14, 0x85, 0x92, 0x53, 0x58, 0x78, 0x88, 0x27, 0x30, 0x65, 0xa0, 0xca, 0x85, 0x03, - 0xbd, 0x25, 0x07, 0xba, 0x25, 0x4e, 0x6f, 0xe3, 0x87, 0x1a, 0x11, 0x9c, 0x6f, 0xb2, 0xea, 0x85, - 0x37, 0x26, 0x3f, 0x2c, 0xc1, 0xf4, 0x41, 0x68, 0xb9, 0x2c, 0xad, 0x27, 0xcf, 0x89, 0x6d, 0x9f, - 0xc8, 0xd8, 0xf6, 0xde, 0x17, 0x3c, 0x47, 0x0a, 0xd9, 0xfc, 0x84, 0xcc, 0xf0, 0x4b, 0x3d, 0x21, - 0x0b, 0x1c, 0x79, 0x08, 0xd3, 0xbc, 0xfe, 0x8b, 0xd3, 0x97, 0x49, 0x4a, 0x81, 0x83, 0xa1, 0x5a, - 0x20, 0x5b, 0x4d, 0x69, 0x8b, 0x85, 0x08, 0xff, 0xab, 0x82, 0x04, 0x85, 0xfa, 0x12, 0x6c, 0xe6, - 0x37, 0x7b, 0x09, 0x46, 0x9e, 0x42, 0x5d, 0x56, 0xdc, 0xad, 0xbe, 0xbc, 0xa3, 0x51, 0xb2, 0x7e, - 0x86, 0x52, 0x2e, 0xa4, 0x05, 0xc8, 0x54, 0x5f, 0x5f, 0x18, 0xb9, 0x0c, 0x62, 0x0c, 0xb7, 0x28, - 0x0a, 0x0b, 0x9f, 0xa1, 0xf6, 0xa9, 0x1d, 0x52, 0x16, 0x89, 0xf6, 0x47, 0xde, 0xbe, 0x50, 0x65, - 0xe6, 0x0d, 0x8c, 0x1f, 0x97, 0x60, 0x61, 0xd8, 0x65, 0xc8, 0x77, 0xa1, 0xb1, 0x21, 0xf2, 0x6a, - 0x10, 0x66, 0xc5, 0x3b, 0xb6, 0xb5, 0xec, 0x14, 0x6c, 0x16, 0x9e, 0x69, 0xa9, 0xe4, 0x64, 0x0d, - 0x6a, 0x7c, 0x0b, 0xfa, 0xf9, 0x8d, 0x20, 0x46, 0x98, 0x58, 0xc2, 0xd4, 0x2b, 0xa8, 0x94, 0x4e, - 0xd9, 0xc1, 0xff, 0x51, 0x86, 0x86, 0xb2, 0x64, 0xe4, 0x5d, 0xa8, 0x6d, 0x47, 0xbb, 0x81, 0x7d, - 0x4a, 0x1d, 0x59, 0xcc, 0xe1, 0x73, 0x3f, 0x37, 0x32, 0x3d, 0x04, 0x1a, 0x19, 0x9a, 0xb4, 0x60, - 0x4e, 0x7c, 0x3d, 0xa6, 0x51, 0x64, 0x75, 0xd2, 0xd1, 0x6f, 0x0f, 0x12, 0xad, 0x29, 0x88, 0xcd, - 0xae, 0xc0, 0x28, 0x73, 0x28, 0xb2, 0x90, 0x3f, 0x06, 0x10, 0x00, 0xbe, 0xca, 0x13, 0xbc, 0x9b, - 0x49, 0xb7, 0xf1, 0x55, 0x39, 0x00, 0x2f, 0x8b, 0x86, 0x8e, 0x48, 0x8a, 0x40, 0x7c, 0x38, 0x15, - 0xd8, 0xa7, 0x93, 0x3f, 0x36, 0xcc, 0x1f, 0x4e, 0x05, 0xf6, 0xa9, 0x39, 0xfe, 0x0c, 0xa6, 0x8a, - 0xd4, 0x7f, 0x55, 0x52, 0xdc, 0x8e, 0x7c, 0x02, 0xf5, 0x6c, 0x69, 0x64, 0xed, 0x7f, 0x4d, 0x7d, - 0x1f, 0x20, 0x51, 0x06, 0x3d, 0x6e, 0xdd, 0x92, 0x05, 0xd8, 0x62, 0xb6, 0xc6, 0x05, 0x2f, 0x4c, - 0x81, 0xe4, 0x63, 0xa8, 0xa2, 0x6d, 0x2e, 0xbe, 0x76, 0x4b, 0x43, 0x7d, 0x95, 0x1b, 0x05, 0x67, - 0x8a, 0x9c, 0xe4, 0xbe, 0x3c, 0xfa, 0x09, 0xeb, 0x5e, 0x29, 0x86, 0x79, 0x3e, 0x95, 0x2c, 0xc6, - 0xe7, 0x27, 0x42, 0xc5, 0x43, 0xfe, 0xbc, 0x04, 0x8b, 0xcf, 0xd6, 0xb6, 0x0c, 0xda, 0x71, 0x23, - 0x26, 0xea, 0xcd, 0x36, 0xcf, 0x1e, 0x37, 0xa0, 0x62, 0x58, 0xcf, 0xe5, 0xb3, 0x81, 0x99, 0x41, - 0xa2, 0x55, 0x42, 0xeb, 0xb9, 0xc1, 0x61, 0xe4, 0x1e, 0xd4, 0x77, 0x68, 0xff, 0x91, 0xe5, 0x3b, - 0x1e, 0x95, 0x0f, 0x06, 0xb0, 0xbb, 0x7b, 0x4a, 0xfb, 0xe6, 0x09, 0x42, 0x8d, 0x9c, 0x80, 0x57, - 0x7e, 0x7b, 0xf1, 0xd1, 0x0e, 0x15, 0x67, 0x93, 0x59, 0x51, 0xf9, 0xf5, 0xe2, 0xa3, 0x53, 0xda, - 0x37, 0x24, 0x46, 0xff, 0x97, 0x32, 0x2c, 0x0c, 0xef, 0x38, 0xf2, 0x11, 0xcc, 0xee, 0x59, 0x51, - 0xf4, 0x3c, 0x08, 0x9d, 0x47, 0x56, 0x74, 0x22, 0xa7, 0x72, 0x6b, 0x90, 0x68, 0xd7, 0x7b, 0x12, - 0x6e, 0x9e, 0x58, 0x91, 0xba, 0x15, 0x0b, 0x0c, 0x3c, 0x37, 0x1f, 0x3c, 0x3d, 0xd8, 0x4b, 0x9f, - 0x35, 0xc8, 0x9d, 0xc3, 0x02, 0xd6, 0x33, 0x8b, 0x6f, 0x1b, 0x52, 0x32, 0xd2, 0x81, 0xcb, 0x43, - 0xb6, 0x90, 0x66, 0x55, 0x1a, 0x22, 0x63, 0x8c, 0x25, 0xba, 0x69, 0xf1, 0xda, 0xb1, 0x19, 0x2a, - 0x18, 0x65, 0x80, 0x61, 0xa9, 0xe4, 0x03, 0x80, 0x67, 0x6b, 0x5b, 0xd8, 0x2e, 0xa5, 0x21, 0x3a, - 0xee, 0x9c, 0x78, 0xd5, 0xc3, 0x85, 0xd8, 0x02, 0xac, 0x96, 0x87, 0x39, 0xb1, 0xee, 0xc3, 0xac, - 0xea, 0x69, 0xbc, 0x3e, 0x51, 0x9a, 0xa4, 0xb5, 0xf4, 0x8d, 0x81, 0x6c, 0x8d, 0x8a, 0x86, 0x41, - 0x79, 0xa4, 0x61, 0x70, 0x17, 0x6a, 0x69, 0x80, 0x52, 0xdf, 0x06, 0xc9, 0x74, 0xd6, 0x37, 0x32, - 0xac, 0xfe, 0x0d, 0x98, 0x91, 0x9e, 0xf4, 0xea, 0x07, 0xb8, 0xfa, 0x8f, 0xca, 0x70, 0xd9, 0xa0, - 0xbc, 0x90, 0x91, 0xef, 0x6d, 0xbe, 0x96, 0x8f, 0x43, 0x0a, 0x1a, 0x9e, 0x5f, 0x45, 0xe9, 0xff, - 0x5a, 0x82, 0xc5, 0x31, 0xb4, 0x5f, 0xe6, 0x06, 0x8b, 0xbc, 0x0f, 0xf5, 0xb6, 0x6b, 0x79, 0xeb, - 0x8e, 0x13, 0xa6, 0xb5, 0x33, 0xa6, 0x23, 0xc7, 0xe5, 0xd9, 0x88, 0x43, 0xd5, 0xe0, 0x92, 0x91, - 0x92, 0x6f, 0x4a, 0xd7, 0xa8, 0x64, 0xc6, 0x4d, 0x9f, 0x9f, 0x80, 0x98, 0x53, 0xfe, 0xf8, 0x44, - 0xff, 0xc7, 0x32, 0x10, 0x01, 0x94, 0xde, 0xe5, 0x06, 0xaf, 0xf5, 0x25, 0x7c, 0xab, 0xb0, 0x80, - 0xcb, 0xca, 0x23, 0x91, 0x21, 0x25, 0x27, 0xaa, 0x84, 0x7f, 0x5c, 0x86, 0x6b, 0xe3, 0x19, 0xbf, - 0xd4, 0x82, 0xde, 0x83, 0x3a, 0x5e, 0x5d, 0x29, 0xef, 0x7c, 0x30, 0x82, 0x8a, 0x7b, 0x2e, 0xa4, - 0xcf, 0x09, 0xc8, 0x31, 0xcc, 0xed, 0x5a, 0x11, 0x7b, 0x44, 0xad, 0x90, 0x1d, 0x51, 0x8b, 0x4d, - 0x90, 0x48, 0xb3, 0x27, 0xae, 0xf8, 0x42, 0xf8, 0x24, 0xe5, 0x1c, 0x7e, 0xe2, 0x5a, 0x10, 0x9b, - 0xb9, 0x4b, 0xf5, 0x62, 0x77, 0xf9, 0xe6, 0x47, 0x30, 0xab, 0xf6, 0x0e, 0x49, 0x0d, 0xaa, 0x4f, - 0x9e, 0x3e, 0xd9, 0x5c, 0xb8, 0x44, 0x1a, 0x30, 0xb3, 0xb7, 0xf9, 0xa4, 0xbd, 0xfd, 0xe4, 0xe1, - 0x42, 0x89, 0xcc, 0x42, 0x6d, 0x7d, 0x6f, 0xcf, 0x78, 0x7a, 0xb8, 0xd9, 0x5e, 0x28, 0x13, 0x80, - 0xe9, 0xf6, 0xe6, 0x93, 0xed, 0xcd, 0xf6, 0x42, 0xa5, 0xb5, 0xf4, 0xf2, 0x7f, 0xee, 0x5c, 0x7a, - 0xf9, 0xd9, 0x9d, 0xd2, 0xcf, 0x3f, 0xbb, 0x53, 0xfa, 0xef, 0xcf, 0xee, 0x94, 0x3e, 0xfd, 0xdf, - 0x3b, 0x97, 0x8e, 0xa6, 0x51, 0x97, 0xfb, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x25, 0x85, - 0x86, 0x64, 0x31, 0x00, 0x00, +func init() { proto.RegisterFile("types.proto", fileDescriptor_types_62fad942422eb27d) } + +var fileDescriptor_types_62fad942422eb27d = []byte{ + // 3850 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x3a, 0x4d, 0x6f, 0x1c, 0xc9, + 0x75, 0xea, 0x99, 0x21, 0x39, 0xf3, 0x86, 0xa4, 0x46, 0x45, 0x4a, 0x1a, 0x49, 0xbb, 0x6a, 0x6e, + 0x2b, 0xbb, 0xd6, 0x3a, 0x5a, 0x32, 0xa6, 0xb2, 0x1b, 0xef, 0xc6, 0xca, 0x2e, 0x87, 0x43, 0x4a, + 0x34, 0x29, 0x89, 0xdb, 0xa4, 0x68, 0x18, 0xf9, 0xe8, 0x34, 0xbb, 0x8b, 0xc3, 0x06, 0x7b, 0xba, + 0xc7, 0xfd, 0x41, 0x69, 0x6e, 0x46, 0x12, 0x20, 0x48, 0x0c, 0xd8, 0x09, 0x02, 0x23, 0x0b, 0x24, + 0x40, 0x72, 0x4c, 0x0e, 0xce, 0x35, 0xa7, 0x1c, 0x02, 0xf8, 0x20, 0xe4, 0xe4, 0xb3, 0xe1, 0xb4, + 0x93, 0xcd, 0xc1, 0xc0, 0xfc, 0x84, 0xbd, 0x24, 0xa8, 0x57, 0xd5, 0xdd, 0xd5, 0x33, 0x43, 0x71, + 0x76, 0xb3, 0x3e, 0x70, 0x4f, 0xd3, 0xf3, 0xbe, 0xaa, 0xde, 0xab, 0x57, 0xaf, 0xde, 0x7b, 0x55, + 0x50, 0x8f, 0xfa, 0x3d, 0x1a, 0x2e, 0xf7, 0x02, 0x3f, 0xf2, 0x49, 0x35, 0xa4, 0xc1, 0xa9, 0x63, + 0xd1, 0xf0, 0xe6, 0x62, 0xc7, 0xef, 0xf8, 0x08, 0x5c, 0x61, 0x5f, 0x1c, 0x7f, 0x53, 0xed, 0xf8, + 0x7e, 0xc7, 0xa5, 0x2b, 0xf8, 0xef, 0x30, 0x3e, 0x5a, 0x89, 0x9c, 0x2e, 0x0d, 0x23, 0xb3, 0xdb, + 0x13, 0x04, 0x0f, 0x3a, 0x4e, 0x74, 0x1c, 0x1f, 0x2e, 0x5b, 0x7e, 0x77, 0xa5, 0x13, 0x98, 0xa7, + 0x4e, 0x64, 0x46, 0x8e, 0xef, 0x99, 0xee, 0x4a, 0x44, 0x5d, 0xda, 0xf3, 0x83, 0x68, 0xc5, 0x75, + 0x0e, 0x57, 0x9e, 0x07, 0x66, 0xaf, 0x47, 0x83, 0x30, 0xfb, 0xe0, 0xec, 0xda, 0x2f, 0x14, 0xa8, + 0x6d, 0x53, 0xda, 0x5b, 0x73, 0x9d, 0x53, 0x4a, 0x56, 0x00, 0xf6, 0x68, 0x70, 0x4a, 0x83, 0x27, + 0x66, 0x97, 0x36, 0x95, 0x25, 0xe5, 0x6e, 0xad, 0x75, 0x79, 0x90, 0xa8, 0xf5, 0x10, 0xa1, 0x86, + 0x67, 0x76, 0xa9, 0x2e, 0x91, 0x90, 0xdf, 0x84, 0x1a, 0xfb, 0x0d, 0x7b, 0xa6, 0x45, 0x9b, 0x25, + 0xa4, 0x9f, 0x1b, 0x24, 0x6a, 0xcd, 0x4b, 0x81, 0x7a, 0x8e, 0x27, 0x6f, 0xc1, 0xcc, 0x0e, 0x35, + 0x43, 0xba, 0xd5, 0x6e, 0x96, 0x97, 0x94, 0xbb, 0xe5, 0xd6, 0xec, 0x20, 0x51, 0xab, 0x2e, 0x03, + 0x19, 0x8e, 0xad, 0xa7, 0x48, 0xb2, 0x05, 0x33, 0x1b, 0x2f, 0x7a, 0x4e, 0x40, 0xc3, 0x66, 0x65, + 0x49, 0xb9, 0x5b, 0x5f, 0xbd, 0xb9, 0xcc, 0xad, 0xb0, 0x9c, 0x5a, 0x61, 0x79, 0x3f, 0xb5, 0x42, + 0x6b, 0xe1, 0x65, 0xa2, 0x5e, 0x1a, 0x24, 0xea, 0x0c, 0xe5, 0x2c, 0x7f, 0xf5, 0x4b, 0x55, 0xd1, + 0x53, 0x7e, 0xed, 0x2f, 0xcb, 0x50, 0x7d, 0x4c, 0x23, 0xd3, 0x36, 0x23, 0x93, 0xbc, 0x06, 0x15, + 0x49, 0xaf, 0xea, 0x20, 0x51, 0x2b, 0xa8, 0x10, 0x42, 0xc9, 0x9d, 0x51, 0x55, 0xa6, 0x06, 0x89, + 0xaa, 0xbc, 0x23, 0xab, 0xf0, 0xbb, 0x50, 0x6f, 0xd3, 0xd0, 0x0a, 0x9c, 0x1e, 0x33, 0x32, 0xaa, + 0x51, 0x6b, 0xdd, 0x18, 0x24, 0xea, 0x55, 0x3b, 0x07, 0xdf, 0xf3, 0xbb, 0x4e, 0x44, 0xbb, 0xbd, + 0xa8, 0xaf, 0xcb, 0xd4, 0x64, 0x07, 0xa6, 0x77, 0xcc, 0x43, 0xea, 0x86, 0xcd, 0xa9, 0xa5, 0xf2, + 0xdd, 0xfa, 0xea, 0xed, 0xe5, 0x74, 0xf1, 0x97, 0xd3, 0x39, 0x2e, 0x73, 0x82, 0x0d, 0x2f, 0x0a, + 0xfa, 0xad, 0xc5, 0x41, 0xa2, 0x36, 0x5c, 0x04, 0x48, 0x22, 0x85, 0x0c, 0xb2, 0x97, 0x5b, 0x69, + 0xfa, 0x5c, 0x2b, 0xbd, 0xfe, 0x32, 0x51, 0x95, 0x41, 0xa2, 0x5e, 0x11, 0x56, 0xca, 0xe5, 0x15, + 0xec, 0x45, 0x96, 0xa0, 0xb4, 0xd5, 0x6e, 0xce, 0xe0, 0xea, 0x34, 0x06, 0x89, 0x3a, 0xeb, 0xd8, + 0xd2, 0xd0, 0xa5, 0xad, 0xf6, 0xcd, 0xf7, 0xa1, 0x2e, 0xcd, 0x91, 0x34, 0xa0, 0x7c, 0x42, 0xfb, + 0xdc, 0xa4, 0x3a, 0xfb, 0x24, 0x8b, 0x30, 0x75, 0x6a, 0xba, 0xb1, 0xb0, 0xa1, 0xce, 0xff, 0x7c, + 0x50, 0xfa, 0xa6, 0xa2, 0xfd, 0xb8, 0x02, 0x55, 0xdd, 0xe7, 0xfe, 0x49, 0xde, 0x86, 0xa9, 0xbd, + 0xc8, 0x8c, 0xd2, 0xd5, 0x58, 0x18, 0x24, 0xea, 0xe5, 0x90, 0x01, 0xa4, 0xf1, 0x38, 0x05, 0x23, + 0xdd, 0x3d, 0x36, 0xc3, 0x74, 0x55, 0x90, 0xb4, 0xc7, 0x00, 0x32, 0x29, 0x52, 0x90, 0xb7, 0xa0, + 0xf2, 0xd8, 0xb7, 0xa9, 0x58, 0x18, 0x32, 0x48, 0xd4, 0xf9, 0xae, 0x6f, 0xcb, 0x84, 0x88, 0x27, + 0xf7, 0xa0, 0xb6, 0x1e, 0x07, 0x01, 0xf5, 0xa2, 0xad, 0x36, 0x3a, 0x59, 0xad, 0x35, 0x3f, 0x48, + 0x54, 0xb0, 0x38, 0x90, 0xb9, 0x63, 0x4e, 0xc0, 0x4c, 0xbd, 0x17, 0x99, 0x41, 0x44, 0xed, 0xe6, + 0xd4, 0x44, 0xa6, 0x66, 0x0e, 0x79, 0x25, 0xe4, 0x2c, 0xc3, 0xa6, 0x16, 0x92, 0xc8, 0x23, 0xa8, + 0x3f, 0x0c, 0x4c, 0x8b, 0xee, 0xd2, 0xc0, 0xf1, 0x6d, 0x5c, 0xc3, 0x72, 0xeb, 0xad, 0x41, 0xa2, + 0x5e, 0xeb, 0x30, 0xb0, 0xd1, 0x43, 0x78, 0xce, 0xfd, 0x59, 0xa2, 0x56, 0xdb, 0x71, 0x80, 0xd6, + 0xd3, 0x65, 0x56, 0xf2, 0xc7, 0x6c, 0x49, 0xc2, 0x08, 0x4d, 0x4b, 0x6d, 0x5c, 0xbd, 0x57, 0x4f, + 0x51, 0x13, 0x53, 0xbc, 0xe6, 0x9a, 0x61, 0x64, 0x04, 0x9c, 0x6f, 0x68, 0x9e, 0xb2, 0x48, 0xa2, + 0x43, 0x75, 0xcf, 0x3a, 0xa6, 0x76, 0xec, 0xd2, 0x66, 0x55, 0x88, 0xcf, 0x7c, 0x37, 0x5d, 0xd2, + 0x94, 0xa2, 0x75, 0x53, 0x88, 0x27, 0xa1, 0x80, 0x48, 0xe6, 0xcf, 0xe4, 0x7c, 0x50, 0xfd, 0xe4, + 0x1f, 0xd5, 0x4b, 0xdf, 0xff, 0xc5, 0xd2, 0x25, 0xed, 0x5f, 0x4b, 0xd0, 0x18, 0x16, 0x42, 0x8e, + 0x60, 0xee, 0x59, 0xcf, 0x36, 0x23, 0xba, 0xee, 0x3a, 0xd4, 0x8b, 0x42, 0xf4, 0x93, 0x57, 0xab, + 0xf5, 0x1b, 0x62, 0xdc, 0x66, 0x8c, 0x8c, 0x86, 0xc5, 0x39, 0x87, 0x14, 0x2b, 0x8a, 0xcd, 0xc7, + 0xe1, 0x51, 0x2d, 0x44, 0x27, 0xfb, 0x7c, 0xe3, 0xf0, 0xe0, 0x78, 0xc6, 0x38, 0x42, 0xac, 0xf0, + 0x21, 0xcf, 0x3e, 0xec, 0xa3, 0x73, 0x4e, 0xee, 0x43, 0x8c, 0x65, 0x8c, 0x0f, 0x31, 0xb0, 0xf6, + 0x2b, 0x05, 0xe6, 0x75, 0x1a, 0xfa, 0x71, 0x60, 0xd1, 0x47, 0xd4, 0xb4, 0x69, 0xc0, 0x76, 0xc0, + 0xb6, 0xe3, 0xd9, 0x62, 0x5b, 0xe1, 0x0e, 0x38, 0x71, 0x3c, 0x79, 0x17, 0x23, 0x9e, 0xfc, 0x16, + 0xcc, 0xec, 0xc5, 0x87, 0x48, 0xca, 0xb7, 0xd5, 0x35, 0x5c, 0xb1, 0xf8, 0xd0, 0x18, 0x22, 0x4f, + 0xc9, 0xc8, 0x0a, 0xcc, 0x1c, 0xd0, 0x20, 0xcc, 0xe3, 0xde, 0x55, 0x36, 0xc3, 0x53, 0x0e, 0x92, + 0x19, 0x04, 0x15, 0xf9, 0x76, 0x1e, 0x7b, 0x45, 0x20, 0x27, 0xa3, 0x11, 0x2f, 0xf7, 0x96, 0xae, + 0x80, 0xc8, 0xde, 0x92, 0x52, 0x69, 0x7f, 0x5e, 0x82, 0x2a, 0x37, 0xe5, 0xc1, 0x2a, 0x0b, 0xe4, + 0x92, 0x8e, 0x18, 0xc8, 0xd9, 0xa4, 0xbf, 0xb0, 0x66, 0x6f, 0x0e, 0x6b, 0x56, 0x67, 0x07, 0x8a, + 0xd0, 0x2c, 0xd7, 0xe7, 0xa3, 0x89, 0xf4, 0x69, 0x08, 0x7d, 0xaa, 0xa9, 0x3e, 0xb9, 0x16, 0xe4, + 0x9b, 0x50, 0xd9, 0xeb, 0x51, 0x4b, 0x44, 0x91, 0x6b, 0x39, 0x37, 0x57, 0x8d, 0xe1, 0x0e, 0x56, + 0x5b, 0xb3, 0x42, 0x42, 0x25, 0xec, 0x51, 0x4b, 0x47, 0x0e, 0x69, 0xb7, 0xfc, 0xac, 0x0c, 0xb3, + 0x32, 0x39, 0xb3, 0xc6, 0x9a, 0x6d, 0x07, 0xb2, 0x35, 0x4c, 0xdb, 0x0e, 0x74, 0x84, 0x92, 0xf7, + 0x01, 0x76, 0xe3, 0x43, 0xd7, 0xb1, 0x90, 0xa6, 0x94, 0x1f, 0x58, 0x3d, 0x84, 0x1a, 0x8c, 0x54, + 0xb2, 0x89, 0x44, 0x4c, 0xee, 0x42, 0xf5, 0x91, 0x1f, 0x46, 0xec, 0x8c, 0x14, 0x76, 0xc1, 0x03, + 0xfb, 0x58, 0xc0, 0xf4, 0x0c, 0x4b, 0x4c, 0xa8, 0xad, 0x77, 0x6d, 0x71, 0xb8, 0x55, 0xf0, 0x70, + 0x7b, 0x73, 0xbc, 0x72, 0xcb, 0x19, 0x1d, 0x3f, 0xe3, 0x5e, 0x13, 0xba, 0x2e, 0x5a, 0x5d, 0xdb, + 0x18, 0x39, 0xeb, 0x72, 0xa9, 0xcc, 0x99, 0xd2, 0x18, 0x21, 0xcc, 0x47, 0x46, 0x43, 0x50, 0xee, + 0x4c, 0x81, 0x80, 0xc8, 0xce, 0x94, 0x9d, 0x3d, 0xef, 0x41, 0xed, 0x59, 0x48, 0xf7, 0x63, 0xcf, + 0xa3, 0x2e, 0x06, 0xde, 0x6a, 0xab, 0xc9, 0xe6, 0x10, 0x87, 0xd4, 0x88, 0x10, 0x2a, 0xcf, 0x21, + 0x23, 0xbd, 0x79, 0x00, 0xf3, 0xc5, 0xe9, 0x8f, 0x39, 0xfe, 0x96, 0xe5, 0xe3, 0xaf, 0xbe, 0xda, + 0xcc, 0x27, 0xb9, 0xee, 0x77, 0xbb, 0xa6, 0xc7, 0xd9, 0x0f, 0x56, 0xe5, 0x83, 0xf1, 0x07, 0x0a, + 0xcc, 0x17, 0xb1, 0x64, 0x19, 0xa6, 0xc5, 0xc1, 0xa0, 0xe0, 0xc1, 0xc0, 0x7c, 0x78, 0x9a, 0x1f, + 0x09, 0x85, 0x83, 0x40, 0x50, 0x31, 0x17, 0x16, 0x12, 0x9a, 0xa5, 0xa5, 0x72, 0xea, 0xc2, 0x16, + 0x07, 0xe9, 0x29, 0x8e, 0x68, 0x30, 0xad, 0xd3, 0x30, 0x76, 0x23, 0xb1, 0xa0, 0xc0, 0xc4, 0x06, + 0x08, 0xd1, 0x05, 0x46, 0xfb, 0x2e, 0xc0, 0xfe, 0xce, 0xde, 0x36, 0xed, 0xef, 0x9a, 0x0e, 0xc6, + 0x93, 0x75, 0x1a, 0x44, 0x38, 0x8d, 0x59, 0x1e, 0x4f, 0x2c, 0x1a, 0x44, 0x72, 0x3c, 0x61, 0x78, + 0x72, 0x07, 0xca, 0xdb, 0xb4, 0x8f, 0x5a, 0xcf, 0xb6, 0xae, 0x0c, 0x12, 0x75, 0xee, 0x84, 0x4a, + 0x71, 0x4b, 0x67, 0x58, 0xed, 0xc7, 0x25, 0xb8, 0xcc, 0xa8, 0xd7, 0xe2, 0xe8, 0xd8, 0x0f, 0x9c, + 0xa8, 0x7f, 0x91, 0x37, 0xf3, 0x87, 0x85, 0xcd, 0xfc, 0xba, 0xb4, 0xd0, 0xb2, 0x86, 0x13, 0xed, + 0xe9, 0xbf, 0xa8, 0xc0, 0xc2, 0x18, 0x2e, 0x72, 0x0f, 0x2a, 0xfb, 0xfd, 0x5e, 0x9a, 0x23, 0x31, + 0x1f, 0xad, 0xb0, 0xe2, 0xe1, 0xb3, 0x44, 0x9d, 0x4d, 0xc9, 0x19, 0x5e, 0x47, 0x2a, 0xb2, 0x0a, + 0xf5, 0x75, 0x37, 0x0e, 0x23, 0x91, 0xbe, 0x73, 0x7b, 0x61, 0x16, 0x67, 0x71, 0x30, 0xcf, 0xdf, + 0x65, 0x22, 0xf2, 0x2e, 0xcc, 0xae, 0x1f, 0x53, 0xeb, 0xc4, 0xf1, 0x3a, 0xdb, 0xb4, 0x1f, 0x36, + 0xcb, 0x4b, 0xe5, 0x74, 0xfd, 0x2c, 0x01, 0x37, 0x4e, 0x68, 0x3f, 0xd4, 0x0b, 0x64, 0xe4, 0x5b, + 0x50, 0xdf, 0x73, 0x3a, 0x5e, 0xca, 0x55, 0x41, 0xae, 0x9b, 0x2c, 0xa5, 0x08, 0x39, 0x18, 0x99, + 0xe4, 0x44, 0x58, 0x22, 0x67, 0x09, 0x9d, 0xee, 0xbb, 0x94, 0xe7, 0xc1, 0x22, 0xa1, 0x0b, 0x18, + 0x40, 0x4e, 0xe8, 0x90, 0x82, 0x6c, 0xc3, 0x0c, 0xfb, 0x78, 0x6c, 0xf6, 0x9a, 0xd3, 0x18, 0x57, + 0xae, 0xca, 0xbb, 0x1e, 0x11, 0x3d, 0xc7, 0xeb, 0xc8, 0x1b, 0xdf, 0xa5, 0x46, 0xd7, 0xec, 0xc9, + 0xae, 0x21, 0x08, 0xc9, 0x77, 0xa0, 0x9e, 0x7b, 0x76, 0xd8, 0x9c, 0x41, 0x81, 0x8b, 0xb9, 0xc0, + 0x1c, 0xd9, 0x52, 0x85, 0xbc, 0xeb, 0x91, 0x1b, 0x32, 0x5d, 0x8c, 0x1e, 0x63, 0x91, 0x15, 0x92, + 0x24, 0x15, 0x82, 0x53, 0xf5, 0x95, 0xc1, 0x49, 0x39, 0x2f, 0x38, 0x69, 0x3a, 0xd4, 0x25, 0xc5, + 0xf8, 0x8e, 0xed, 0xfa, 0x59, 0xa2, 0x2c, 0x76, 0x2c, 0x83, 0xe8, 0x02, 0x43, 0x54, 0x98, 0xda, + 0xf1, 0x2d, 0xd3, 0x15, 0x5b, 0xbf, 0x36, 0x48, 0xd4, 0x29, 0x97, 0x01, 0x74, 0x0e, 0xd7, 0xfe, + 0x53, 0x81, 0xc6, 0x6e, 0xe0, 0x9f, 0x3a, 0xcc, 0xf5, 0xf7, 0xfd, 0x13, 0xea, 0x1d, 0x7c, 0x83, + 0x6c, 0xa5, 0xab, 0xa0, 0x20, 0xd7, 0x7d, 0xc6, 0x85, 0xab, 0xf0, 0x59, 0xa2, 0xbe, 0x75, 0x6e, + 0x55, 0x89, 0xd6, 0x4f, 0x57, 0x49, 0xaa, 0x45, 0x4a, 0x93, 0x27, 0x37, 0xe7, 0xd4, 0x22, 0x2a, + 0x4c, 0xe1, 0x54, 0xc5, 0x36, 0x46, 0xad, 0x22, 0x06, 0xd0, 0x39, 0x5c, 0xda, 0x3f, 0x7f, 0x5b, + 0x1a, 0xd1, 0xef, 0x02, 0x07, 0x96, 0x8f, 0x0a, 0x81, 0x45, 0xaa, 0x12, 0x8b, 0x2a, 0x4e, 0x14, + 0x59, 0x4c, 0x58, 0x1c, 0xc7, 0xf5, 0x25, 0x2e, 0xbe, 0xf6, 0x37, 0x25, 0x98, 0x67, 0x85, 0x9a, + 0x63, 0xe1, 0x00, 0xe1, 0x45, 0x36, 0xfd, 0xef, 0x15, 0x4c, 0xff, 0x9a, 0x94, 0xc3, 0x48, 0x0a, + 0x4e, 0x64, 0xf8, 0x13, 0x20, 0xa3, 0x3c, 0xe4, 0x19, 0xcc, 0xca, 0x50, 0xb4, 0x7e, 0xa1, 0x98, + 0x1a, 0xde, 0xa5, 0xad, 0xab, 0x62, 0x94, 0xb9, 0x10, 0xf9, 0x0c, 0xdc, 0x01, 0xa1, 0x5e, 0x10, + 0xa3, 0xfd, 0x75, 0x09, 0xe6, 0xa4, 0xa8, 0x7e, 0x91, 0x57, 0xe0, 0x41, 0x61, 0x05, 0x6e, 0x49, + 0xa7, 0x6a, 0xae, 0xdf, 0x44, 0x0b, 0xf0, 0x10, 0xae, 0x8c, 0xb0, 0x0c, 0x1f, 0x91, 0xca, 0x04, + 0x47, 0x24, 0x4f, 0x5a, 0xf8, 0xff, 0x75, 0xdf, 0x3b, 0x72, 0x3a, 0x07, 0xf7, 0xbf, 0x8a, 0x49, + 0x8b, 0xac, 0x21, 0x5a, 0xeb, 0xfe, 0x39, 0x06, 0xfe, 0xd1, 0x14, 0x2c, 0x8c, 0xe1, 0x22, 0x6b, + 0xd0, 0xd8, 0xa3, 0x21, 0x4e, 0x9c, 0x5a, 0x7e, 0x60, 0x3b, 0x5e, 0x47, 0xd8, 0x09, 0x0b, 0xc6, + 0x90, 0xe3, 0x8c, 0x20, 0x45, 0xea, 0x23, 0xe4, 0xd8, 0x9e, 0xe1, 0x92, 0xb7, 0xda, 0xc2, 0x84, + 0xbc, 0x3d, 0x23, 0x16, 0x09, 0xdb, 0x33, 0x29, 0x01, 0xd9, 0x81, 0x85, 0xdd, 0xc0, 0x7f, 0xd1, + 0xc7, 0x0c, 0x25, 0x64, 0x45, 0x89, 0x48, 0x65, 0x18, 0x1f, 0x26, 0x25, 0x3d, 0x86, 0x36, 0x30, + 0xa1, 0x09, 0x0d, 0x56, 0xbf, 0xf0, 0x9c, 0x66, 0x1c, 0x1b, 0xf9, 0x00, 0xa6, 0xd6, 0x62, 0xdb, + 0x89, 0x84, 0x81, 0xa5, 0x7c, 0x03, 0xc1, 0x5c, 0xd5, 0xd6, 0x9c, 0x30, 0xcd, 0x94, 0xc9, 0x80, + 0x3a, 0x67, 0x21, 0x1f, 0x33, 0x9f, 0x73, 0xa8, 0x17, 0x6d, 0xd9, 0x2e, 0x65, 0x27, 0x9e, 0x1f, + 0x47, 0x68, 0xea, 0x72, 0xeb, 0xce, 0x20, 0x51, 0x17, 0x78, 0x47, 0xc2, 0x70, 0x6c, 0x97, 0x1a, + 0x11, 0x47, 0x17, 0xb2, 0xf9, 0x51, 0x6e, 0xf2, 0x5d, 0xb8, 0xda, 0x76, 0x42, 0xcb, 0xf7, 0x3c, + 0x6a, 0x45, 0xfc, 0x68, 0xb4, 0x31, 0x21, 0xe7, 0x75, 0x0b, 0x13, 0x7b, 0xdd, 0xce, 0x08, 0x0c, + 0x7e, 0xa6, 0xda, 0x06, 0xcb, 0xd1, 0x3f, 0x4b, 0xd4, 0x4a, 0xcb, 0xf7, 0x5d, 0x7d, 0xbc, 0x04, + 0x36, 0xdb, 0xac, 0xf5, 0xbb, 0xe5, 0x45, 0x34, 0x38, 0x35, 0x5d, 0xd1, 0xfb, 0xc3, 0xd9, 0x9e, + 0x50, 0xda, 0x33, 0x4c, 0x86, 0x35, 0x1c, 0x81, 0x2e, 0xce, 0x76, 0x84, 0x9b, 0x6c, 0x4a, 0x22, + 0xd7, 0xfd, 0xd8, 0x8b, 0x1e, 0x9b, 0x2f, 0x30, 0x23, 0x2a, 0xf3, 0x0a, 0x4b, 0x12, 0x69, 0x31, + 0xb4, 0xd1, 0x35, 0x5f, 0xe8, 0xa3, 0x2c, 0xe4, 0xb7, 0xa1, 0x86, 0x99, 0x0b, 0xcb, 0x70, 0x9b, + 0x35, 0xd4, 0x94, 0xed, 0x21, 0xc0, 0xac, 0xc6, 0x30, 0xe3, 0xe8, 0x38, 0x53, 0x2e, 0x27, 0xd4, + 0x3e, 0x29, 0x43, 0x5d, 0x5a, 0x24, 0x56, 0xbb, 0x48, 0xe9, 0x33, 0xd6, 0x2e, 0x2c, 0x7d, 0x96, + 0x6b, 0x17, 0x4c, 0x9c, 0xef, 0xb1, 0x1c, 0xab, 0xc3, 0x36, 0x1f, 0xf7, 0x35, 0x6c, 0xbc, 0x06, + 0x08, 0x91, 0x1b, 0xaf, 0x9c, 0x86, 0xec, 0x40, 0x03, 0x07, 0x11, 0x5e, 0x1b, 0x3e, 0xd3, 0xb7, + 0x84, 0xaf, 0x2d, 0x0d, 0x12, 0xf5, 0x35, 0x74, 0x08, 0x43, 0x78, 0x79, 0x68, 0xc4, 0x81, 0x23, + 0xc9, 0x18, 0xe1, 0x24, 0x7f, 0xaf, 0xc0, 0x3c, 0x02, 0x37, 0x4e, 0xa9, 0x17, 0xa1, 0xb0, 0x8a, + 0xe8, 0x0e, 0x64, 0xad, 0xfa, 0xbd, 0x28, 0x70, 0xbc, 0xce, 0x01, 0xab, 0x17, 0xc3, 0xd6, 0x1f, + 0x30, 0xcf, 0xfb, 0x79, 0xa2, 0xbe, 0xf7, 0xf9, 0x1a, 0xff, 0x42, 0x48, 0x38, 0x48, 0xd4, 0x9b, + 0x7c, 0x8a, 0x14, 0x07, 0x1c, 0x9a, 0xe0, 0xd0, 0x5c, 0xc8, 0xa6, 0x98, 0xdd, 0xbe, 0x79, 0xe8, + 0x52, 0x8c, 0x99, 0x53, 0xa8, 0xea, 0xed, 0x5c, 0x4e, 0xc4, 0x50, 0x18, 0x37, 0x47, 0xe4, 0x64, + 0x5c, 0xda, 0xff, 0x2a, 0x52, 0x7b, 0xfd, 0xe2, 0x86, 0xcf, 0xf7, 0x0b, 0xe1, 0xf3, 0x7a, 0xce, + 0x9d, 0xe9, 0xc6, 0xd0, 0xe3, 0x02, 0xa7, 0x76, 0x19, 0xe6, 0x0a, 0x44, 0xda, 0x3f, 0x94, 0x60, + 0x51, 0xa7, 0x21, 0x8d, 0x76, 0xcd, 0x30, 0x7c, 0xee, 0x07, 0x36, 0x3f, 0xf2, 0x2f, 0xf0, 0xe1, + 0xd2, 0x2e, 0x58, 0x47, 0x93, 0x4a, 0xa0, 0x11, 0x35, 0x27, 0x3a, 0x61, 0xfe, 0x49, 0x81, 0xe6, + 0x59, 0xac, 0xcc, 0x4a, 0xcf, 0x42, 0x5a, 0x68, 0x7b, 0xc5, 0x21, 0x0d, 0x74, 0x84, 0x92, 0x1b, + 0x50, 0x7e, 0xa6, 0xef, 0x08, 0x0b, 0xcd, 0x0c, 0x12, 0xb5, 0x1c, 0x07, 0xae, 0xce, 0x60, 0xac, + 0x58, 0x59, 0x0f, 0x28, 0xb6, 0xca, 0x2b, 0x93, 0x17, 0x2b, 0x16, 0x67, 0x19, 0x2e, 0x56, 0x84, + 0x24, 0xed, 0x27, 0x25, 0xb8, 0x35, 0x66, 0xaa, 0xd4, 0x0a, 0x68, 0x14, 0x5e, 0xe4, 0x35, 0xdd, + 0x2e, 0xac, 0xe9, 0xdb, 0xaf, 0x5c, 0x53, 0xae, 0xed, 0x44, 0x4b, 0xfb, 0x1f, 0x0a, 0xa8, 0xe7, + 0x48, 0x20, 0x77, 0x60, 0xfa, 0xe9, 0xfe, 0xee, 0x76, 0xda, 0x5f, 0xe3, 0x2a, 0xfa, 0x3d, 0x3c, + 0xbc, 0x75, 0x81, 0x22, 0xef, 0xc0, 0xf4, 0xc7, 0xfa, 0xba, 0x6f, 0xa7, 0xfd, 0x0e, 0xcc, 0x31, + 0xbe, 0x17, 0x18, 0x56, 0xf1, 0xda, 0x47, 0x10, 0xc9, 0x8b, 0x5f, 0xfe, 0xd2, 0x16, 0x9f, 0x65, + 0x88, 0x6b, 0x96, 0x45, 0xc3, 0x50, 0xa7, 0xdf, 0x8b, 0x69, 0x18, 0x7d, 0x25, 0x33, 0xc4, 0x82, + 0x86, 0x13, 0x2d, 0xf2, 0xbf, 0x97, 0x60, 0x61, 0x0c, 0xd7, 0x39, 0x5b, 0x57, 0x4d, 0x4b, 0x53, + 0xa9, 0x9b, 0x81, 0xa5, 0x69, 0xda, 0x6d, 0x58, 0x4b, 0xaf, 0x0e, 0x99, 0x21, 0xe6, 0xe5, 0x36, + 0x7a, 0x3a, 0x0c, 0xc3, 0xbe, 0xf2, 0x4a, 0xf1, 0xd7, 0x11, 0x03, 0xe4, 0x2e, 0xc8, 0xd4, 0x97, + 0xd5, 0x05, 0xd1, 0xfe, 0x4c, 0x19, 0xb2, 0xe1, 0xa6, 0xe3, 0x46, 0x34, 0x20, 0xd7, 0xf0, 0xa6, + 0x96, 0x5b, 0x70, 0x7a, 0x90, 0xa8, 0x25, 0xc7, 0xd6, 0x4b, 0x5b, 0xed, 0xcc, 0xb6, 0xa5, 0xb1, + 0xb6, 0xfd, 0x9d, 0xc9, 0x4c, 0x87, 0x36, 0x47, 0xd3, 0x09, 0x83, 0x69, 0x7f, 0x5a, 0x82, 0x69, + 0x66, 0xfd, 0x8b, 0xec, 0xd9, 0xef, 0x15, 0x3c, 0x7b, 0xb1, 0xd8, 0x48, 0x9c, 0xc8, 0xa1, 0x7f, + 0xa5, 0x00, 0xe4, 0xc4, 0xe4, 0xdb, 0x30, 0xf3, 0x14, 0xaf, 0xf6, 0xd3, 0xdb, 0xc9, 0xa1, 0xe6, + 0xa4, 0x40, 0xb6, 0x6e, 0xa4, 0x6b, 0xed, 0x73, 0x80, 0x6c, 0x05, 0x41, 0x43, 0x1e, 0xc2, 0xd4, + 0x9a, 0xeb, 0xfa, 0xcf, 0x47, 0xef, 0x0d, 0x98, 0xa4, 0x75, 0xdf, 0xb3, 0x1d, 0x2e, 0xec, 0xba, + 0x10, 0x76, 0xd9, 0x64, 0xe4, 0xb2, 0x6b, 0x23, 0x3f, 0x3b, 0x84, 0xdb, 0xd4, 0x4b, 0x6f, 0x19, + 0xcf, 0x96, 0x73, 0x4d, 0xc8, 0x99, 0xb7, 0xa9, 0x27, 0x37, 0xea, 0x91, 0x5b, 0xfb, 0x69, 0x85, + 0xb7, 0x21, 0xd3, 0xe9, 0x3d, 0x80, 0xd9, 0x4d, 0x3f, 0x78, 0x6e, 0x06, 0xf6, 0x5a, 0x87, 0x7a, + 0xfc, 0x3a, 0xa0, 0x8a, 0x17, 0x49, 0x73, 0x47, 0x1c, 0x6e, 0x98, 0x0c, 0x91, 0xa5, 0xe5, 0x05, + 0x72, 0xf2, 0x14, 0xe6, 0x1e, 0x9b, 0x2f, 0x44, 0xde, 0xbb, 0xbf, 0xcf, 0x0f, 0xe6, 0x72, 0xeb, + 0xed, 0x41, 0xa2, 0xde, 0xe8, 0x9a, 0x2f, 0xd2, 0x74, 0xd9, 0x88, 0x22, 0xf7, 0x8c, 0x1b, 0xef, + 0x22, 0x3f, 0x71, 0x61, 0x7e, 0xd7, 0x0f, 0x22, 0x31, 0x08, 0x2b, 0x31, 0xb9, 0xbe, 0x0b, 0xb9, + 0xbe, 0x6c, 0x1a, 0x98, 0x33, 0xb7, 0x56, 0x5e, 0x26, 0xaa, 0xf2, 0xf3, 0x44, 0x05, 0x06, 0xe2, + 0x1a, 0xb1, 0x81, 0x59, 0x8e, 0x6c, 0x1c, 0x65, 0x12, 0xe4, 0xec, 0xb5, 0x28, 0x9b, 0x3c, 0x80, + 0x2b, 0xac, 0x62, 0x72, 0x8e, 0x1c, 0xcb, 0x8c, 0xe8, 0xa6, 0x1f, 0x74, 0xcd, 0x48, 0x3c, 0x1b, + 0xc0, 0xe7, 0x31, 0xac, 0xda, 0x62, 0x92, 0xba, 0x66, 0xa4, 0x8f, 0x52, 0x92, 0xdf, 0x3f, 0xbb, + 0x2c, 0x7c, 0x67, 0x90, 0xa8, 0xaf, 0x8f, 0x29, 0x0b, 0xcf, 0xb0, 0xc2, 0x98, 0x02, 0xb1, 0xf3, + 0xea, 0x02, 0xf1, 0x1b, 0xa2, 0xe9, 0xfc, 0xc6, 0x19, 0x45, 0x62, 0x61, 0xa0, 0x57, 0x96, 0x8b, + 0xab, 0x50, 0x6e, 0xed, 0x6e, 0x62, 0xd7, 0x5c, 0x94, 0x3a, 0xd4, 0x3b, 0x36, 0x3d, 0x8b, 0xda, + 0x79, 0x2d, 0x2f, 0x5f, 0xf8, 0xb4, 0x76, 0x37, 0xb5, 0x1f, 0x95, 0x61, 0xbe, 0xe8, 0x77, 0x44, + 0x83, 0xe9, 0x1d, 0xbf, 0xe3, 0x78, 0x69, 0xeb, 0x11, 0x1b, 0xda, 0x2e, 0x42, 0x74, 0x81, 0x21, + 0x6f, 0x02, 0x64, 0xb9, 0x72, 0x7a, 0x0e, 0x88, 0xc7, 0x38, 0x12, 0x82, 0xfc, 0x11, 0xc0, 0x13, + 0xdf, 0xa6, 0xe2, 0xde, 0xb1, 0x2c, 0xb6, 0x60, 0x56, 0xf1, 0xf0, 0xbb, 0x34, 0x5e, 0x35, 0x7d, + 0x4d, 0x54, 0x4d, 0xe2, 0xf5, 0xcc, 0x20, 0x51, 0xaf, 0x7a, 0xbe, 0x4d, 0x47, 0xaf, 0x1c, 0x25, + 0x89, 0xe4, 0x01, 0x4c, 0xe9, 0xb1, 0x4b, 0xd3, 0x2b, 0xcd, 0x79, 0x69, 0x2f, 0xc5, 0x2e, 0xcd, + 0x77, 0x62, 0x10, 0x0f, 0xdf, 0x5d, 0x30, 0x00, 0xf9, 0x10, 0x60, 0x3b, 0x3e, 0xa4, 0x0f, 0x03, + 0x3f, 0xee, 0xa5, 0x77, 0x1d, 0xea, 0x20, 0x51, 0x6f, 0x9d, 0xc4, 0x87, 0x34, 0xf0, 0x68, 0x44, + 0x43, 0xa3, 0x83, 0x48, 0x79, 0xfc, 0x9c, 0x85, 0xe8, 0x30, 0x23, 0xc2, 0xb2, 0x78, 0xe2, 0xf3, + 0xc6, 0x19, 0xa7, 0xb1, 0xb4, 0xad, 0x31, 0xff, 0x09, 0x38, 0xb8, 0x70, 0x07, 0xc2, 0x41, 0x5a, + 0x1b, 0xae, 0x9f, 0xc1, 0x9a, 0x5f, 0xcb, 0x28, 0xe7, 0x5d, 0xcb, 0x68, 0x3f, 0x55, 0xa0, 0xc2, + 0x94, 0x24, 0xef, 0x42, 0x2d, 0x7d, 0x80, 0x90, 0xf2, 0x5d, 0x1f, 0x24, 0xea, 0x42, 0x90, 0x02, + 0xe5, 0x9b, 0xd4, 0x8c, 0x92, 0x0d, 0x75, 0x40, 0x83, 0xc3, 0x74, 0x6d, 0x71, 0xa8, 0x53, 0x06, + 0x90, 0x87, 0x42, 0x0a, 0x46, 0xfa, 0x9d, 0x63, 0x1a, 0xa4, 0x57, 0xd0, 0x48, 0xfa, 0x9c, 0x01, + 0x64, 0x52, 0xa4, 0x20, 0x2b, 0x30, 0xb3, 0x66, 0xf1, 0x78, 0x5c, 0x41, 0xb9, 0x68, 0x0c, 0xd3, + 0x1a, 0x09, 0xba, 0x82, 0x4a, 0x7b, 0x03, 0x6a, 0x59, 0x94, 0x20, 0x8b, 0x30, 0x85, 0x1f, 0x3c, + 0xb6, 0xe9, 0xfc, 0x0f, 0x1e, 0x7c, 0xec, 0xe8, 0xbc, 0xc8, 0x3d, 0xd5, 0x33, 0x0f, 0x3e, 0xa6, + 0xd8, 0x44, 0xcd, 0xd4, 0x7f, 0x99, 0x06, 0xc8, 0x89, 0x09, 0x85, 0xf9, 0xa7, 0x5b, 0xed, 0xf5, + 0x2d, 0x9b, 0x7a, 0x91, 0x13, 0x39, 0x74, 0x4c, 0x23, 0x7b, 0xe3, 0x45, 0x44, 0x03, 0xcf, 0x74, + 0x05, 0x4d, 0xbf, 0xf5, 0x86, 0x18, 0xe0, 0x86, 0xef, 0xd8, 0x96, 0xe1, 0x64, 0xac, 0x72, 0xd8, + 0x2d, 0x0a, 0x65, 0xc3, 0xec, 0xad, 0x3d, 0xde, 0x91, 0x86, 0x29, 0x4d, 0x3e, 0x4c, 0x68, 0x76, + 0xdd, 0x33, 0x86, 0x29, 0x0a, 0x25, 0x27, 0xd0, 0x78, 0x88, 0xbd, 0x14, 0x69, 0xa0, 0xf2, 0xb9, + 0x03, 0xdd, 0x11, 0x03, 0xdd, 0xe2, 0x7d, 0x98, 0xf1, 0x43, 0x8d, 0x08, 0xce, 0x37, 0x59, 0xe5, + 0xdc, 0xbb, 0xcf, 0xef, 0x2b, 0x30, 0xbd, 0x1f, 0x98, 0x4e, 0x94, 0xe6, 0x93, 0x67, 0xc4, 0xb6, + 0x8f, 0x45, 0x6c, 0x7b, 0xf7, 0x73, 0x76, 0x84, 0xb8, 0xec, 0x41, 0xa2, 0x36, 0x22, 0xfc, 0x92, + 0xcb, 0x25, 0x8e, 0x23, 0x0f, 0x61, 0x9a, 0xe5, 0x7f, 0x71, 0xfa, 0xc6, 0x50, 0x4a, 0x70, 0x30, + 0x54, 0x73, 0x64, 0xab, 0x29, 0x6c, 0xd1, 0x08, 0xf1, 0xbf, 0x2c, 0x88, 0x53, 0xc8, 0x6f, 0x3a, + 0x67, 0xfe, 0x7f, 0x6f, 0x3a, 0xc9, 0x53, 0xa8, 0x89, 0x8c, 0xbb, 0xd5, 0x17, 0xb7, 0xad, 0xd2, + 0xa9, 0x9f, 0xa1, 0xa4, 0xa7, 0x25, 0x1c, 0x64, 0xc8, 0xef, 0xa8, 0xf4, 0x5c, 0x06, 0xd1, 0x87, + 0x9b, 0x8d, 0x85, 0x85, 0xcf, 0x50, 0xa2, 0x38, 0xe5, 0x8d, 0xcc, 0xbc, 0x11, 0x29, 0xcb, 0xcc, + 0x5b, 0x91, 0x3f, 0x54, 0xa0, 0x31, 0xec, 0x32, 0xe4, 0x5b, 0x50, 0x5f, 0xe7, 0xe7, 0xaa, 0x1f, + 0x64, 0xc9, 0x3b, 0x36, 0xa8, 0xad, 0x14, 0x6c, 0x14, 0x1e, 0x5c, 0xca, 0xe4, 0x64, 0x15, 0xaa, + 0x6c, 0x0b, 0x7a, 0xf9, 0xdd, 0x3e, 0x46, 0x98, 0x58, 0xc0, 0xe4, 0xcb, 0xe4, 0x94, 0x4e, 0xda, + 0xc1, 0xff, 0x56, 0x82, 0xba, 0xb4, 0x64, 0xe4, 0x6d, 0xa8, 0x6e, 0x85, 0x3b, 0xbe, 0x75, 0x42, + 0x6d, 0x91, 0xcc, 0xe1, 0xc3, 0x5d, 0x27, 0x34, 0x5c, 0x04, 0xea, 0x19, 0x9a, 0xb4, 0x60, 0x8e, + 0x7f, 0x3d, 0xa6, 0x61, 0x68, 0x76, 0xd2, 0xd1, 0x5f, 0x1b, 0x24, 0x6a, 0x93, 0x13, 0x1b, 0x5d, + 0x8e, 0x91, 0xe6, 0x50, 0x64, 0x21, 0x7f, 0x08, 0xc0, 0x01, 0x6c, 0x95, 0x27, 0x28, 0xbd, 0xd3, + 0x6d, 0x7c, 0x55, 0x0c, 0xc0, 0xd2, 0xa2, 0xa1, 0x12, 0x49, 0x12, 0x88, 0x4f, 0x20, 0x7d, 0xeb, + 0x64, 0xf2, 0x67, 0xc3, 0xf9, 0x13, 0x48, 0xdf, 0x3a, 0x31, 0xc6, 0xd7, 0x60, 0xb2, 0x48, 0xed, + 0x97, 0x8a, 0xe4, 0x76, 0xe4, 0x63, 0xa8, 0x65, 0x4b, 0x23, 0x72, 0xff, 0x6b, 0xf2, 0x4b, 0x1f, + 0x81, 0xd2, 0xe9, 0x51, 0xeb, 0x96, 0x48, 0xc0, 0x16, 0xb2, 0x35, 0x2e, 0x78, 0x61, 0x0a, 0x24, + 0x1f, 0x41, 0x05, 0x6d, 0x73, 0xfe, 0x05, 0x7a, 0x1a, 0xea, 0x2b, 0xcc, 0x28, 0x38, 0x53, 0xe4, + 0x24, 0xf7, 0x45, 0xe9, 0xc7, 0xad, 0x7b, 0xa5, 0x18, 0xe6, 0xd9, 0x54, 0xb2, 0x18, 0x9f, 0x57, + 0x84, 0x92, 0x87, 0xfc, 0x89, 0x02, 0x0b, 0xcf, 0x56, 0x37, 0x75, 0xda, 0x71, 0xc2, 0x88, 0xe7, + 0x9b, 0x6d, 0x76, 0x7a, 0xdc, 0x80, 0xb2, 0x6e, 0x3e, 0x17, 0x0f, 0x80, 0xb0, 0x95, 0x16, 0x98, + 0xcf, 0x75, 0x06, 0x23, 0xf7, 0xa0, 0xb6, 0x4d, 0xfb, 0x8f, 0x4c, 0xcf, 0x76, 0xa9, 0x78, 0xfa, + 0x83, 0xf7, 0x34, 0x27, 0xb4, 0x6f, 0x1c, 0x23, 0x54, 0xcf, 0x09, 0x58, 0xe6, 0xb7, 0x1b, 0x1f, + 0x6e, 0x53, 0x5e, 0x9b, 0xcc, 0xf2, 0xcc, 0xaf, 0x17, 0x1f, 0x62, 0x3b, 0x87, 0x63, 0xb4, 0x7f, + 0x2e, 0x41, 0x63, 0x78, 0xc7, 0x91, 0x0f, 0x61, 0x36, 0x6d, 0x13, 0x3d, 0x32, 0xc3, 0x63, 0x31, + 0x95, 0x5b, 0x83, 0x44, 0xbd, 0xde, 0x13, 0x70, 0xe3, 0xd8, 0x0c, 0xe5, 0xad, 0x58, 0x60, 0x60, + 0x67, 0xf3, 0xbe, 0x68, 0x25, 0x49, 0x3b, 0x27, 0xf2, 0xa3, 0x9e, 0x51, 0x7c, 0xa5, 0x94, 0x92, + 0x91, 0x0e, 0x5c, 0x1e, 0xb2, 0x85, 0x30, 0xab, 0xd4, 0x10, 0x19, 0x63, 0x2c, 0xde, 0x17, 0x8f, + 0x57, 0x8f, 0x8c, 0x40, 0xc2, 0x48, 0x03, 0x0c, 0x4b, 0x25, 0xef, 0x03, 0x3c, 0x5b, 0xdd, 0xc4, + 0x8b, 0x0f, 0x1a, 0xa0, 0xe3, 0xce, 0xf1, 0xf7, 0x79, 0x4c, 0x88, 0xc5, 0xc1, 0x72, 0x7a, 0x98, + 0x13, 0x6b, 0x1e, 0xcc, 0xca, 0x9e, 0xc6, 0xf2, 0x13, 0xe9, 0xba, 0xa3, 0x9a, 0xbe, 0x16, 0x12, + 0x97, 0x1c, 0xbc, 0x61, 0x50, 0x1a, 0x69, 0x18, 0xdc, 0x85, 0x6a, 0x1a, 0xa0, 0xe4, 0x57, 0x7e, + 0xe2, 0x38, 0xeb, 0xeb, 0x19, 0x56, 0xfb, 0x1a, 0xcc, 0x08, 0x4f, 0x7a, 0xf5, 0x53, 0x7a, 0xed, + 0x07, 0x25, 0xb8, 0xac, 0x53, 0x96, 0xc8, 0x88, 0x97, 0x73, 0x5f, 0xc9, 0x67, 0x5e, 0x05, 0x0d, + 0xcf, 0xce, 0xa2, 0xb4, 0x9f, 0x28, 0xb0, 0x30, 0x86, 0xf6, 0x8b, 0xdc, 0x45, 0x93, 0xf7, 0xa0, + 0xd6, 0x76, 0x4c, 0x77, 0xcd, 0xb6, 0x83, 0x34, 0x77, 0xc6, 0xe3, 0xc8, 0x76, 0xd8, 0x69, 0xc4, + 0xa0, 0x72, 0x70, 0xc9, 0x48, 0xc9, 0xd7, 0x85, 0x6b, 0x94, 0x33, 0xe3, 0xa6, 0x0f, 0xc9, 0x80, + 0xcf, 0x29, 0x7f, 0x46, 0xa6, 0xfd, 0x5d, 0x09, 0x08, 0x07, 0x0a, 0xef, 0x72, 0xfc, 0x0b, 0xfd, + 0x9c, 0xa6, 0x55, 0x58, 0xc0, 0x25, 0xe9, 0xb9, 0xd7, 0x90, 0x92, 0x13, 0x65, 0xc2, 0x3f, 0x2c, + 0xc1, 0xb5, 0xf1, 0x8c, 0x5f, 0x68, 0x41, 0xef, 0x41, 0x0d, 0x2f, 0xa1, 0xa5, 0x17, 0x7b, 0x18, + 0x41, 0xf9, 0x8d, 0x35, 0xd2, 0xe7, 0x04, 0xe4, 0x08, 0xe6, 0x76, 0xcc, 0x30, 0x7a, 0x44, 0xcd, + 0x20, 0x3a, 0xa4, 0x66, 0x34, 0xc1, 0x41, 0x9a, 0x3d, 0x56, 0xc7, 0xb7, 0xfe, 0xc7, 0x29, 0xe7, + 0xf0, 0x63, 0xf5, 0x82, 0xd8, 0xcc, 0x5d, 0x2a, 0xe7, 0xbb, 0xcb, 0xd7, 0x3f, 0x84, 0x59, 0xb9, + 0x77, 0x48, 0xaa, 0x50, 0x79, 0xf2, 0xf4, 0xc9, 0x46, 0xe3, 0x12, 0xa9, 0xc3, 0xcc, 0xee, 0xc6, + 0x93, 0xf6, 0xd6, 0x93, 0x87, 0x0d, 0x85, 0xcc, 0x42, 0x75, 0x6d, 0x77, 0x57, 0x7f, 0x7a, 0xb0, + 0xd1, 0x6e, 0x94, 0x08, 0xc0, 0x74, 0x7b, 0xe3, 0xc9, 0xd6, 0x46, 0xbb, 0x51, 0x6e, 0x2d, 0xbe, + 0xfc, 0xef, 0xdb, 0x97, 0x5e, 0x7e, 0x7a, 0x5b, 0xf9, 0xd9, 0xa7, 0xb7, 0x95, 0xff, 0xfa, 0xf4, + 0xb6, 0xf2, 0xc9, 0xff, 0xdc, 0xbe, 0x74, 0x38, 0x8d, 0xba, 0xdc, 0xff, 0xbf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x07, 0xe6, 0x2b, 0xdd, 0x2e, 0x35, 0x00, 0x00, } diff --git a/lib/services/types.proto b/lib/services/types.proto index ddb8bd2212449..0b0b3f816d745 100644 --- a/lib/services/types.proto +++ b/lib/services/types.proto @@ -11,30 +11,39 @@ option (gogoproto.goproto_getters_all) = false; message KeepAlive { // ServerName is a server name to keep alive - string ServerName = 1 [(gogoproto.jsontag) = "server_name"]; + string ServerName = 1 [ (gogoproto.jsontag) = "server_name" ]; // Namespace is a server namespace - string Namespace = 2 [(gogoproto.jsontag) = "namespace"]; + string Namespace = 2 [ (gogoproto.jsontag) = "namespace" ]; // LeaseID is ID of the lease - int64 LeaseID = 3 [(gogoproto.jsontag) = "lease_id"]; + int64 LeaseID = 3 [ (gogoproto.jsontag) = "lease_id" ]; // Expires is set to update expiry time - google.protobuf.Timestamp Expires = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "expires"]; + google.protobuf.Timestamp Expires = 4 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expires" + ]; } // Metadata is resource metadata message Metadata { // Name is an object name - string Name = 1 [(gogoproto.jsontag) = "name"]; - // Namespace is object namespace. The field should be called "namespace" - // when it returns in Teleport 2.4. - string Namespace = 2 [(gogoproto.jsontag) = "-"]; - // Description is object description - string Description = 3 [(gogoproto.jsontag) = "description,omitempty"]; - // Labels is a set of labels - map Labels = 5 [(gogoproto.jsontag) = "labels,omitempty"]; - // Expires is a global expiry time header can be set on any resource in the system. - google.protobuf.Timestamp Expires = 6 [(gogoproto.stdtime) = true, (gogoproto.nullable) = true, (gogoproto.jsontag) = "expires,omitempty"]; + string Name = 1 [ (gogoproto.jsontag) = "name" ]; + // Namespace is object namespace. The field should be called "namespace" + // when it returns in Teleport 2.4. + string Namespace = 2 [ (gogoproto.jsontag) = "-" ]; + // Description is object description + string Description = 3 [ (gogoproto.jsontag) = "description,omitempty" ]; + // Labels is a set of labels + map Labels = 5 [ (gogoproto.jsontag) = "labels,omitempty" ]; + // Expires is a global expiry time header can be set on any resource in the + // system. + google.protobuf.Timestamp Expires = 6 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = true, + (gogoproto.jsontag) = "expires,omitempty" + ]; // ID is a record ID - int64 ID = 7 [(gogoproto.jsontag) = "id,omitempty"]; + int64 ID = 7 [ (gogoproto.jsontag) = "id,omitempty" ]; }; // Rotation is a status of the rotation of the certificate authority @@ -42,50 +51,73 @@ message Rotation { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; - // State could be one of "init" or "in_progress". - string State = 1 [(gogoproto.jsontag) = "state,omitempty"]; - // Phase is the current rotation phase. - string Phase = 2 [(gogoproto.jsontag) = "phase,omitempty"]; - // Mode sets manual or automatic rotation mode. - string Mode = 3 [(gogoproto.jsontag) = "mode,omitempty"]; - // CurrentID is the ID of the rotation operation - // to differentiate between rotation attempts. - string CurrentID = 4 [(gogoproto.jsontag) = "current_id"]; - // Started is set to the time when rotation has been started - // in case if the state of the rotation is "in_progress". - google.protobuf.Timestamp Started = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "started,omitempty"]; - // GracePeriod is a period during which old and new CA - // are valid for checking purposes, but only new CA is issuing certificates. - int64 GracePeriod = 6 [(gogoproto.jsontag) = "grace_period,omitempty", (gogoproto.casttype) = "Duration"]; - // LastRotated specifies the last time of the completed rotation. - google.protobuf.Timestamp LastRotated = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "last_rotated,omitempty"]; - // Schedule is a rotation schedule - used in - // automatic mode to switch beetween phases. - RotationSchedule Schedule = 8 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "schedule,omitempty"]; + // State could be one of "init" or "in_progress". + string State = 1 [ (gogoproto.jsontag) = "state,omitempty" ]; + // Phase is the current rotation phase. + string Phase = 2 [ (gogoproto.jsontag) = "phase,omitempty" ]; + // Mode sets manual or automatic rotation mode. + string Mode = 3 [ (gogoproto.jsontag) = "mode,omitempty" ]; + // CurrentID is the ID of the rotation operation + // to differentiate between rotation attempts. + string CurrentID = 4 [ (gogoproto.jsontag) = "current_id" ]; + // Started is set to the time when rotation has been started + // in case if the state of the rotation is "in_progress". + google.protobuf.Timestamp Started = 5 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.jsontag) = "started,omitempty" + ]; + // GracePeriod is a period during which old and new CA + // are valid for checking purposes, but only new CA is issuing certificates. + int64 GracePeriod = 6 + [ (gogoproto.jsontag) = "grace_period,omitempty", (gogoproto.casttype) = "Duration" ]; + // LastRotated specifies the last time of the completed rotation. + google.protobuf.Timestamp LastRotated = 7 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.jsontag) = "last_rotated,omitempty" + ]; + // Schedule is a rotation schedule - used in + // automatic mode to switch beetween phases. + RotationSchedule Schedule = 8 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "schedule,omitempty" ]; } // RotationSchedule is a rotation schedule setting time switches // for different phases. message RotationSchedule { - // UpdateClients specifies time to switch to the "Update clients" phase - google.protobuf.Timestamp UpdateClients = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "update_clients,omitempty"]; - // UpdateServers specifies time to switch to the "Update servers" phase. - google.protobuf.Timestamp UpdateServers = 2 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "update_servers,omitempty"]; - // Standby specifies time to switch to the "Standby" phase. - google.protobuf.Timestamp Standby = 3 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "standby,omitempty"]; + // UpdateClients specifies time to switch to the "Update clients" phase + google.protobuf.Timestamp UpdateClients = 1 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.jsontag) = "update_clients,omitempty" + ]; + // UpdateServers specifies time to switch to the "Update servers" phase. + google.protobuf.Timestamp UpdateServers = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.jsontag) = "update_servers,omitempty" + ]; + // Standby specifies time to switch to the "Standby" phase. + google.protobuf.Timestamp Standby = 3 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.jsontag) = "standby,omitempty" + ]; } // ResorceHeader is a shared resource header // used in cases when only type and name is known message ResourceHeader { - // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind,omitempty"]; - // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version,omitempty"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata,omitempty"]; + // Kind is a resource kind + string Kind = 1 [ (gogoproto.jsontag) = "kind,omitempty" ]; + // SubKind is an optional resource sub kind, used in some resources + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version,omitempty" ]; + // Metadata is User metadata + Metadata Metadata = 4 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata,omitempty" ]; } // ServerV2 represents a Node, Proxy or Auth server in a Teleport cluster @@ -94,52 +126,53 @@ message ServerV2 { option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a server spec - ServerSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + ServerSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // ServerSpecV2 is a specification for V2 Server -message ServerSpecV2 { - // Addr is server host:port address - string Addr = 1 [(gogoproto.jsontag) = "addr"]; - // PublicAddr is the public address this cluster can be reached at. - string PublicAddr = 2 [(gogoproto.jsontag) = "public_addr,omitempty"]; - // Hostname is server hostname - string Hostname = 3 [(gogoproto.jsontag) = "hostname"]; - // CmdLabels is server dynamic labels - map CmdLabels = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "cmd_labels,omitempty"]; - // Rotation specifies server rotation - Rotation Rotation = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "rotation,omitempty"]; - // UseTunnel indicates that connections to this server should occur over a - // reverse tunnel. - bool UseTunnel = 6 [(gogoproto.jsontag) = "use_tunnel,omitempty"]; +message ServerSpecV2 { + // Addr is server host:port address + string Addr = 1 [ (gogoproto.jsontag) = "addr" ]; + // PublicAddr is the public address this cluster can be reached at. + string PublicAddr = 2 [ (gogoproto.jsontag) = "public_addr,omitempty" ]; + // Hostname is server hostname + string Hostname = 3 [ (gogoproto.jsontag) = "hostname" ]; + // CmdLabels is server dynamic labels + map CmdLabels = 4 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "cmd_labels,omitempty" ]; + // Rotation specifies server rotation + Rotation Rotation = 5 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "rotation,omitempty" ]; + // UseTunnel indicates that connections to this server should occur over a + // reverse tunnel. + bool UseTunnel = 6 [ (gogoproto.jsontag) = "use_tunnel,omitempty" ]; } // CommandLabelV2 is a label that has a value as a result of the // output generated by running command, e.g. hostname message CommandLabelV2 { - // Period is a time between command runs - int64 Period = 1 [(gogoproto.jsontag) = "period", (gogoproto.casttype) = "Duration"]; - // Command is a command to run - repeated string Command = 2 [(gogoproto.jsontag) = "command"]; - // Result captures standard output - string Result = 3 [(gogoproto.jsontag) = "result"]; + // Period is a time between command runs + int64 Period = 1 [ (gogoproto.jsontag) = "period", (gogoproto.casttype) = "Duration" ]; + // Command is a command to run + repeated string Command = 2 [ (gogoproto.jsontag) = "command" ]; + // Result captures standard output + string Result = 3 [ (gogoproto.jsontag) = "result" ]; } - // TLSKeyPair is a TLS key pair message TLSKeyPair { - // Cert is a PEM encoded TLS cert - bytes Cert = 1 [(gogoproto.jsontag) = "cert,omitempty"]; - // Key is a PEM encoded TLS key - bytes Key = 2 [(gogoproto.jsontag) = "key,omitempty"]; + // Cert is a PEM encoded TLS cert + bytes Cert = 1 [ (gogoproto.jsontag) = "cert,omitempty" ]; + // Key is a PEM encoded TLS key + bytes Key = 2 [ (gogoproto.jsontag) = "key,omitempty" ]; } // CertAuthorityV2 is version 2 resource spec for Cert Authority @@ -147,51 +180,54 @@ message CertAuthorityV2 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; + string Version = 3 [ (gogoproto.jsontag) = "version" ]; // Metadata is connector metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec contains cert authority specification - CertAuthoritySpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + CertAuthoritySpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // CertAuthoritySpecV2 is a host or user certificate authority that // can check and if it has private key stored as well, sign it too message CertAuthoritySpecV2 { - // Type is either user or host certificate authority - string Type = 1 [(gogoproto.jsontag) = "type", (gogoproto.casttype) = "CertAuthType"]; - // DELETE IN(2.7.0) this field is deprecated, - // as resource name matches cluster name after migrations. - // and this property is enforced by the auth server code. - // ClusterName identifies cluster name this authority serves, - // for host authorities that means base hostname of all servers, - // for user authorities that means organization name - string ClusterName = 2 [(gogoproto.jsontag) = "cluster_name"]; - // Checkers is a list of SSH public keys that can be used to check - // certificate signatures - repeated bytes CheckingKeys = 3 [(gogoproto.jsontag) = "checking_keys"]; - // SigningKeys is a list of private keys used for signing - repeated bytes SigningKeys = 4 [(gogoproto.jsontag) = "signing_keys,omitempty"]; - // Roles is a list of roles assumed by users signed by this CA - repeated string Roles = 5 [(gogoproto.jsontag) = "roles,omitempty"]; - // RoleMap specifies role mappings to remote roles - repeated RoleMapping RoleMap = 6 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "role_map,omitempty"]; - // TLS is a list of TLS key pairs - repeated TLSKeyPair TLSKeyPairs = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "tls_key_pairs,omitempty"]; - // Rotation is a status of the certificate authority rotation - Rotation Rotation = 8 [(gogoproto.nullable) = true, (gogoproto.jsontag) = "rotation,omitempty"]; + // Type is either user or host certificate authority + string Type = 1 [ (gogoproto.jsontag) = "type", (gogoproto.casttype) = "CertAuthType" ]; + // DELETE IN(2.7.0) this field is deprecated, + // as resource name matches cluster name after migrations. + // and this property is enforced by the auth server code. + // ClusterName identifies cluster name this authority serves, + // for host authorities that means base hostname of all servers, + // for user authorities that means organization name + string ClusterName = 2 [ (gogoproto.jsontag) = "cluster_name" ]; + // Checkers is a list of SSH public keys that can be used to check + // certificate signatures + repeated bytes CheckingKeys = 3 [ (gogoproto.jsontag) = "checking_keys" ]; + // SigningKeys is a list of private keys used for signing + repeated bytes SigningKeys = 4 [ (gogoproto.jsontag) = "signing_keys,omitempty" ]; + // Roles is a list of roles assumed by users signed by this CA + repeated string Roles = 5 [ (gogoproto.jsontag) = "roles,omitempty" ]; + // RoleMap specifies role mappings to remote roles + repeated RoleMapping RoleMap = 6 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "role_map,omitempty" ]; + // TLS is a list of TLS key pairs + repeated TLSKeyPair TLSKeyPairs = 7 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "tls_key_pairs,omitempty" ]; + // Rotation is a status of the certificate authority rotation + Rotation Rotation = 8 + [ (gogoproto.nullable) = true, (gogoproto.jsontag) = "rotation,omitempty" ]; } // RoleMappping provides mapping of remote roles to local roles // for trusted clusters message RoleMapping { - // Remote specifies remote role name to map from - string Remote = 1 [(gogoproto.jsontag) = "remote"]; - // Local specifies local roles to map to - repeated string Local = 2 [(gogoproto.jsontag) = "local"]; + // Remote specifies remote role name to map from + string Remote = 1 [ (gogoproto.jsontag) = "remote" ]; + // Local specifies local roles to map to + repeated string Local = 2 [ (gogoproto.jsontag) = "local" ]; } // ProvisionTokenV1 is a provisioning token V1 @@ -199,14 +235,22 @@ message ProvisionTokenV1 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; - // Roles is a list of roles associated with the token, - // that will be converted to metadata in the SSH and X509 - // certificates issued to the user of the token - repeated string Roles = 1 [(gogoproto.jsontag) = "roles", (gogoproto.casttype) = "github.com/gravitational/teleport.Role"]; - // Expires is a global expiry time header can be set on any resource in the system. - google.protobuf.Timestamp Expires = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "expires,omitempty"]; - // Token is a token name - string Token = 3 [(gogoproto.jsontag) = "token"]; + // Roles is a list of roles associated with the token, + // that will be converted to metadata in the SSH and X509 + // certificates issued to the user of the token + repeated string Roles = 1 [ + (gogoproto.jsontag) = "roles", + (gogoproto.casttype) = "github.com/gravitational/teleport.Role" + ]; + // Expires is a global expiry time header can be set on any resource in the + // system. + google.protobuf.Timestamp Expires = 2 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expires,omitempty" + ]; + // Token is a token name + string Token = 3 [ (gogoproto.jsontag) = "token" ]; } // ProvisionTokenV2 specifies provisioning token @@ -215,49 +259,51 @@ message ProvisionTokenV2 { option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a provisioning token V2 spec - ProvisionTokenSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + ProvisionTokenSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // ProvisionTokenSpecV2 is a specification for V2 token -message ProvisionTokenSpecV2 { - // Roles is a list of roles associated with the token, - // that will be converted to metadata in the SSH and X509 - // certificates issued to the user of the token - repeated string Roles = 1 [(gogoproto.jsontag) = "roles", (gogoproto.casttype) = "github.com/gravitational/teleport.Role"]; +message ProvisionTokenSpecV2 { + // Roles is a list of roles associated with the token, + // that will be converted to metadata in the SSH and X509 + // certificates issued to the user of the token + repeated string Roles = 1 [ + (gogoproto.jsontag) = "roles", + (gogoproto.casttype) = "github.com/gravitational/teleport.Role" + ]; } - // StaticTokensV2 implements the StaticTokens interface. message StaticTokensV2 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a provisioning token V2 spec - StaticTokensSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + StaticTokensSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } - // StaticTokensSpecV2 is the actual data we care about for StaticTokensSpecV2. -message StaticTokensSpecV2 { - // StaticTokens is a list of tokens that can be used to add nodes to the - // cluster. - repeated ProvisionTokenV1 StaticTokens = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "static_tokens"]; +message StaticTokensSpecV2 { + // StaticTokens is a list of tokens that can be used to add nodes to the + // cluster. + repeated ProvisionTokenV1 StaticTokens = 1 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "static_tokens" ]; } // ClusterNameV2 implements the ClusterName interface. @@ -266,22 +312,22 @@ message ClusterNameV2 { option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a cluster name V2 spec - ClusterNameSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + ClusterNameSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // ClusterNameSpecV2 is the actual data we care about for ClusterName. -message ClusterNameSpecV2 { - // ClusterName is the name of the cluster. Changing this value once the - // cluster is setup can and will cause catastrophic problems. - string ClusterName = 1 [(gogoproto.jsontag) = "cluster_name"]; +message ClusterNameSpecV2 { + // ClusterName is the name of the cluster. Changing this value once the + // cluster is setup can and will cause catastrophic problems. + string ClusterName = 1 [ (gogoproto.jsontag) = "cluster_name" ]; } // ClusterConfigV3 implements the ClusterConfig interface. @@ -290,102 +336,170 @@ message ClusterConfigV3 { option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a cluster config V3 spec - ClusterConfigSpecV3 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + ClusterConfigSpecV3 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // ClusterConfigSpecV3 is the actual data we care about for ClusterConfig. message ClusterConfigSpecV3 { - // SessionRecording controls where (or if) the session is recorded. - string SessionRecording = 1 [(gogoproto.jsontag) = "session_recording"]; + // SessionRecording controls where (or if) the session is recorded. + string SessionRecording = 1 [ (gogoproto.jsontag) = "session_recording" ]; // ClusterID is the unique cluster ID that is set once during the first auth - // server startup. - string ClusterID = 2 [(gogoproto.jsontag) = "cluster_id"]; + // server startup. + string ClusterID = 2 [ (gogoproto.jsontag) = "cluster_id" ]; - // ProxyChecksHostKeys is used to control if the proxy will check host keys - // when in recording mode. - string ProxyChecksHostKeys = 3 [(gogoproto.jsontag) = "proxy_checks_host_keys"]; + // ProxyChecksHostKeys is used to control if the proxy will check host keys + // when in recording mode. + string ProxyChecksHostKeys = 3 [ (gogoproto.jsontag) = "proxy_checks_host_keys" ]; - // Audit is a section with audit config - AuditConfig Audit = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "audit"]; + // Audit is a section with audit config + AuditConfig Audit = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "audit" ]; - // ClientIdleTimeout sets global cluster default setting for client idle timeouts - int64 ClientIdleTimeout = 5 [(gogoproto.jsontag) = "client_idle_timeout", (gogoproto.casttype) = "Duration"]; + // ClientIdleTimeout sets global cluster default setting for client idle + // timeouts + int64 ClientIdleTimeout = 5 + [ (gogoproto.jsontag) = "client_idle_timeout", (gogoproto.casttype) = "Duration" ]; - // DisconnectExpiredCert provides disconnect expired certificate setting - - // if true, connections with expired client certificates will get disconnected - bool DisconnectExpiredCert = 6 [(gogoproto.jsontag) = "disconnect_expired_cert", (gogoproto.casttype) = "Bool"]; + // DisconnectExpiredCert provides disconnect expired certificate setting - + // if true, connections with expired client certificates will get disconnected + bool DisconnectExpiredCert = 6 + [ (gogoproto.jsontag) = "disconnect_expired_cert", (gogoproto.casttype) = "Bool" ]; - // KeepAliveInterval is the interval the server sends keep-alive messsages - // to the client at. - int64 KeepAliveInterval = 7 [(gogoproto.jsontag) = "keep_alive_interval", (gogoproto.casttype) = "Duration"]; + // KeepAliveInterval is the interval the server sends keep-alive messsages + // to the client at. + int64 KeepAliveInterval = 7 + [ (gogoproto.jsontag) = "keep_alive_interval", (gogoproto.casttype) = "Duration" ]; - // KeepAliveCountMax is the number of keep-alive messages that can be missed before - // the server disconnects the connection to the client. - int64 KeepAliveCountMax = 8 [(gogoproto.jsontag) = "keep_alive_count_max"]; + // KeepAliveCountMax is the number of keep-alive messages that can be missed + // before + // the server disconnects the connection to the client. + int64 KeepAliveCountMax = 8 [ (gogoproto.jsontag) = "keep_alive_count_max" ]; // LocalAuth is true if local authentication is enabled. - bool LocalAuth = 9 [(gogoproto.jsontag) = "local_auth", (gogoproto.casttype) = "Bool"]; + bool LocalAuth = 9 [ (gogoproto.jsontag) = "local_auth", (gogoproto.casttype) = "Bool" ]; } // AuditConfig represents audit log settings in the cluster message AuditConfig { // Type is audit backend type - string Type = 1 [(gogoproto.jsontag) = "type,omitempty"]; + string Type = 1 [ (gogoproto.jsontag) = "type,omitempty" ]; // Region is a region setting for audit sessions used by cloud providers - string Region = 2 [(gogoproto.jsontag) = "region,omitempty"]; + string Region = 2 [ (gogoproto.jsontag) = "region,omitempty" ]; // AuditSessionsURI is a parameter where to upload sessions - string AuditSessionsURI = 3 [(gogoproto.jsontag) = "audit_sessions_uri,omitempty"]; + string AuditSessionsURI = 3 [ (gogoproto.jsontag) = "audit_sessions_uri,omitempty" ]; // AuditEventsURI is a parameter with all supported outputs // for audit events - wrappers.StringValues AuditEventsURI = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "audit_events_uri,omitempty", (gogoproto.customtype) = "github.com/gravitational/teleport/lib/wrappers.Strings"]; - // AuditTableName is a DB table name used for audits - // Deprecated in favor of AuditEventsURI - // DELETE IN (3.1.0) - string AuditTableName = 5 [(gogoproto.jsontag) = "audit_table_name,omitempty"]; + wrappers.StringValues AuditEventsURI = 4 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "audit_events_uri,omitempty", + (gogoproto.customtype) = "github.com/gravitational/teleport/lib/wrappers.Strings" + ]; + // AuditTableName is a DB table name used for audits + // Deprecated in favor of AuditEventsURI + // DELETE IN (3.1.0) + string AuditTableName = 5 [ (gogoproto.jsontag) = "audit_table_name,omitempty" ]; } // Namespace represents namespace resource specification -message Namespace { +message Namespace { // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a namespace spec - NamespaceSpec Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + NamespaceSpec Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // NamespaceSpec is a namespace specificateion -message NamespaceSpec { +message NamespaceSpec {} + +message ResetPasswordTokenV3 { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.stringer) = false; + + // Kind is a resource kind + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; + // SubKind is an optional resource sub kind, used in some resources + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is ResetPasswordToken metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; + // Spec is an ResetPasswordToken specification + ResetPasswordTokenSpecV3 Spec = 5 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; +} + +message ResetPasswordTokenSpecV3 { + // User is user name associated with this token + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // URL is this token URL + string URL = 2 [ (gogoproto.jsontag) = "url" ]; + // Created holds information about when the token was created + google.protobuf.Timestamp Created = 4 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "created,omitempty" + ]; +} + +message ResetPasswordTokenSecretsV3 { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.stringer) = false; + + // Kind is a resource kind + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; + // SubKind is an optional resource sub kind, used in some resources + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is ResetPasswordTokenSecrets metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; + // Spec is an ResetPasswordTokenSecrets specification + ResetPasswordTokenSecretsSpecV3 Spec = 5 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; +} + +message ResetPasswordTokenSecretsSpecV3 { + // OTPKey is is a secret value of one time password secret generator + string OTPKey = 1 [ (gogoproto.jsontag) = "opt_key" ]; + // OTPKey is is a secret value of one time password secret generator + string QRCode = 2 [ (gogoproto.jsontag) = "qr_code,omitempty" ]; + // Created holds information about when the token was created + google.protobuf.Timestamp Created = 3 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "created,omitempty" + ]; } // AccessRequest represents an access request resource specification -message AccessRequestV3 { +message AccessRequestV3 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is AccessRequest metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is AccessRequest metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is an AccessReqeust specification - AccessRequestSpecV3 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + AccessRequestSpecV3 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // RequestState represents the state of a request for escalated privilege. @@ -406,182 +520,227 @@ enum RequestState { // AccessRequestSpec is the specification for AccessRequest message AccessRequestSpecV3 { // User is the name of the user to whom the roles will be applied. - string User = 1 [(gogoproto.jsontag) = "user"]; + string User = 1 [ (gogoproto.jsontag) = "user" ]; // Roles is the name of the roles being requested. - repeated string Roles = 2 [(gogoproto.jsontag) = "roles"]; + repeated string Roles = 2 [ (gogoproto.jsontag) = "roles" ]; // State is the current state of this access request. - RequestState State = 3 [(gogoproto.jsontag) = "state,omitempty"]; - // Created encodes the time at which the request was registered with the auth server. - google.protobuf.Timestamp Created = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "created,omitempty"]; - // Expires constrains the maximum lifetime of any login session for which this request is active. - google.protobuf.Timestamp Expires = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "expires,omitempty"]; + RequestState State = 3 [ (gogoproto.jsontag) = "state,omitempty" ]; + // Created encodes the time at which the request was registered with the auth + // server. + google.protobuf.Timestamp Created = 4 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "created,omitempty" + ]; + // Expires constrains the maximum lifetime of any login session for which this + // request is active. + google.protobuf.Timestamp Expires = 5 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expires,omitempty" + ]; } // AccessRequestFilter encodes filter params for access requests. message AccessRequestFilter { // ID specifies a request ID if set. - string ID = 1 [(gogoproto.jsontag) = "id"]; + string ID = 1 [ (gogoproto.jsontag) = "id" ]; // User specifies a username if set. - string User = 2 [(gogoproto.jsontag) = "user"]; + string User = 2 [ (gogoproto.jsontag) = "user" ]; // RequestState filters for requests in a specific state. - RequestState State = 3 [(gogoproto.jsontag) = "state"]; + RequestState State = 3 [ (gogoproto.jsontag) = "state" ]; } // RoleV3 represents role resource specification -message RoleV3 { +message RoleV3 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a role specification - RoleSpecV3 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + RoleSpecV3 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // RoleSpecV3 is role specification for RoleV3. message RoleSpecV3 { - // Options is for OpenSSH options like agent forwarding. - RoleOptions Options = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "options,omitempty"]; - // Allow is the set of conditions evaluated to grant access. - RoleConditions Allow = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "allow,omitempty"]; - // Deny is the set of conditions evaluated to deny access. Deny takes priority over allow. - RoleConditions Deny = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "deny,omitempty"]; + // Options is for OpenSSH options like agent forwarding. + RoleOptions Options = 1 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "options,omitempty" ]; + // Allow is the set of conditions evaluated to grant access. + RoleConditions Allow = 2 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "allow,omitempty" ]; + // Deny is the set of conditions evaluated to deny access. Deny takes priority + // over allow. + RoleConditions Deny = 3 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "deny,omitempty" ]; } // RoleOptions is a set of role options -message RoleOptions { +message RoleOptions { // ForwardAgent is SSH agent forwarding. - bool ForwardAgent = 1 [(gogoproto.jsontag) = "forward_agent", (gogoproto.casttype) = "Bool"]; - - // MaxSessionTTL defines how long a SSH session can last for. - int64 MaxSessionTTL = 2 [(gogoproto.jsontag) = "max_session_ttl,omitempty", (gogoproto.casttype) = "Duration"]; - - // PortForwarding defines if the certificate will have "permit-port-forwarding" - // in the certificate. PortForwarding is "yes" if not set, - // that's why this is a pointer - BoolValue PortForwarding = 3 [(gogoproto.nullable) = true, (gogoproto.jsontag) = "port_forwarding,omitempty", (gogoproto.customtype) = "BoolOption"]; - - // CertificateFormat defines the format of the user certificate to allow - // compatibility with older versions of OpenSSH. - string CertificateFormat = 4 [(gogoproto.jsontag) = "cert_format"]; - - // ClientIdleTimeout sets disconnect clients on idle timeout behavior, - // if set to 0 means do not disconnect, otherwise is set to the idle - // duration. - int64 ClientIdleTimeout = 5 [(gogoproto.jsontag) = "client_idle_timeout,omitempty", (gogoproto.casttype) = "Duration"]; - - // DisconnectExpiredCert sets disconnect clients on expired certificates. - bool DisconnectExpiredCert = 6 [(gogoproto.nullable) = true, (gogoproto.jsontag) = "disconnect_expired_cert,omitempty", (gogoproto.casttype) = "Bool"]; + bool ForwardAgent = 1 [ (gogoproto.jsontag) = "forward_agent", (gogoproto.casttype) = "Bool" ]; + + // MaxSessionTTL defines how long a SSH session can last for. + int64 MaxSessionTTL = 2 + [ (gogoproto.jsontag) = "max_session_ttl,omitempty", (gogoproto.casttype) = "Duration" ]; + + // PortForwarding defines if the certificate will have + // "permit-port-forwarding" + // in the certificate. PortForwarding is "yes" if not set, + // that's why this is a pointer + BoolValue PortForwarding = 3 [ + (gogoproto.nullable) = true, + (gogoproto.jsontag) = "port_forwarding,omitempty", + (gogoproto.customtype) = "BoolOption" + ]; + + // CertificateFormat defines the format of the user certificate to allow + // compatibility with older versions of OpenSSH. + string CertificateFormat = 4 [ (gogoproto.jsontag) = "cert_format" ]; + + // ClientIdleTimeout sets disconnect clients on idle timeout behavior, + // if set to 0 means do not disconnect, otherwise is set to the idle + // duration. + int64 ClientIdleTimeout = 5 [ + (gogoproto.jsontag) = "client_idle_timeout,omitempty", + (gogoproto.casttype) = "Duration" + ]; + + // DisconnectExpiredCert sets disconnect clients on expired certificates. + bool DisconnectExpiredCert = 6 [ + (gogoproto.nullable) = true, + (gogoproto.jsontag) = "disconnect_expired_cert,omitempty", + (gogoproto.casttype) = "Bool" + ]; // BPF defines what events to record for the BPF-based session recorder. - repeated string BPF = 7 [(gogoproto.jsontag) = "enhanced_recording,omitempty"]; + repeated string BPF = 7 [ (gogoproto.jsontag) = "enhanced_recording,omitempty" ]; } - // RoleConditions is a set of conditions that must all match to be allowed or // denied access. message RoleConditions { - // Logins is a list of *nix system logins. - repeated string Logins = 1 [(gogoproto.jsontag) = "logins"]; + // Logins is a list of *nix system logins. + repeated string Logins = 1 [ (gogoproto.jsontag) = "logins" ]; - // Namespaces is a list of namespaces (used to partition a cluster). The - // field should be called "namespaces" when it returns in Teleport 2.4. - repeated string Namespaces = 2 [(gogoproto.jsontag) = "-"]; + // Namespaces is a list of namespaces (used to partition a cluster). The + // field should be called "namespaces" when it returns in Teleport 2.4. + repeated string Namespaces = 2 [ (gogoproto.jsontag) = "-" ]; - // NodeLabels is a map of node labels (used to dynamically grant access to nodes). - wrappers.LabelValues NodeLabels = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "node_labels,omitempty", (gogoproto.customtype) = "Labels"]; + // NodeLabels is a map of node labels (used to dynamically grant access to + // nodes). + wrappers.LabelValues NodeLabels = 3 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "node_labels,omitempty", + (gogoproto.customtype) = "Labels" + ]; - // Rules is a list of rules and their access levels. Rules are a high level - // construct used for access control. - repeated Rule Rules = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "rules,omitempty"]; + // Rules is a list of rules and their access levels. Rules are a high level + // construct used for access control. + repeated Rule Rules = 4 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "rules,omitempty" ]; - // KubeGroups is a list of kubernetes groups - repeated string KubeGroups = 5 [(gogoproto.jsontag) = "kubernetes_groups,omitempty"]; + // KubeGroups is a list of kubernetes groups + repeated string KubeGroups = 5 [ (gogoproto.jsontag) = "kubernetes_groups,omitempty" ]; - AccessRequestConditions Request = 6 [(gogoproto.jsontag) = "request,omitempty"]; + AccessRequestConditions Request = 6 [ (gogoproto.jsontag) = "request,omitempty" ]; } -// AccessRequestConditions is a matcher for allow/deny restrictions on access-requests. +// AccessRequestConditions is a matcher for allow/deny restrictions on +// access-requests. message AccessRequestConditions { // Roles is the name of roles which will match the request rule. - repeated string Roles = 1 [(gogoproto.jsontag) = "roles,omitempty"]; + repeated string Roles = 1 [ (gogoproto.jsontag) = "roles,omitempty" ]; } // Rule represents allow or deny rule that is executed to check // if user or service have access to resource -message Rule { - // Resources is a list of resources - repeated string Resources = 1 [(gogoproto.jsontag) = "resources,omitempty"]; - // Verbs is a list of verbs - repeated string Verbs = 2 [(gogoproto.jsontag) = "verbs,omitempty"]; - // Where specifies optional advanced matcher - string Where = 3 [(gogoproto.jsontag) = "where,omitempty"]; - // Actions specifies optional actions taken when this rule matches - repeated string Actions = 4 [(gogoproto.jsontag) = "actions,omitempty"]; +message Rule { + // Resources is a list of resources + repeated string Resources = 1 [ (gogoproto.jsontag) = "resources,omitempty" ]; + // Verbs is a list of verbs + repeated string Verbs = 2 [ (gogoproto.jsontag) = "verbs,omitempty" ]; + // Where specifies optional advanced matcher + string Where = 3 [ (gogoproto.jsontag) = "where,omitempty" ]; + // Actions specifies optional actions taken when this rule matches + repeated string Actions = 4 [ (gogoproto.jsontag) = "actions,omitempty" ]; } // BoolValue is a wrapper around bool, used in cases // whenever bool value can have different default value when missing -message BoolValue { - bool Value = 1; -} +message BoolValue { bool Value = 1; } // UserV2 is version 2 resource spec of the user -message UserV2 { +message UserV2 { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is User metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is User metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; // Spec is a user specification - UserSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + UserSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // UserSpecV2 is a specification for V2 user -message UserSpecV2 { - // OIDCIdentities lists associated OpenID Connect identities - // that let user log in using externally verified identity - repeated ExternalIdentity OIDCIdentities = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "oidc_identities,omitempty"]; - - // SAMLIdentities lists associated SAML identities - // that let user log in using externally verified identity - repeated ExternalIdentity SAMLIdentities = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "saml_identities,omitempty"]; - - // GithubIdentities list associated Github OAuth2 identities - // that let user log in using externally verified identity - repeated ExternalIdentity GithubIdentities = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "github_identities,omitempty"]; - - // Roles is a list of roles assigned to user - repeated string Roles = 4 [(gogoproto.jsontag) = "roles,omitempty"]; - - // Traits are key/value pairs received from an identity provider (through - // OIDC claims or SAML assertions) or from a system administrator for local - // accounts. Traits are used to populate role variables. - wrappers.LabelValues Traits = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "traits,omitempty", (gogoproto.customtype) = "github.com/gravitational/teleport/lib/wrappers.Traits"]; - - // Status is a login status of the user - LoginStatus Status = 6 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "status,omitempty"]; - - // Expires if set sets TTL on the user - google.protobuf.Timestamp Expires = 7 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "expires"]; - - // CreatedBy holds information about agent or person created this user - CreatedBy CreatedBy = 8 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "created_by,omitempty"]; - - // LocalAuths hold sensitive data necessary for performing local authentication - LocalAuthSecrets LocalAuth = 9 [(gogoproto.jsontag) = "local_auth,omitempty"]; +message UserSpecV2 { + // OIDCIdentities lists associated OpenID Connect identities + // that let user log in using externally verified identity + repeated ExternalIdentity OIDCIdentities = 1 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "oidc_identities,omitempty" ]; + + // SAMLIdentities lists associated SAML identities + // that let user log in using externally verified identity + repeated ExternalIdentity SAMLIdentities = 2 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "saml_identities,omitempty" ]; + + // GithubIdentities list associated Github OAuth2 identities + // that let user log in using externally verified identity + repeated ExternalIdentity GithubIdentities = 3 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "github_identities,omitempty" ]; + + // Roles is a list of roles assigned to user + repeated string Roles = 4 [ (gogoproto.jsontag) = "roles,omitempty" ]; + + // Traits are key/value pairs received from an identity provider (through + // OIDC claims or SAML assertions) or from a system administrator for local + // accounts. Traits are used to populate role variables. + wrappers.LabelValues Traits = 5 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "traits,omitempty", + (gogoproto.customtype) = "github.com/gravitational/teleport/lib/wrappers.Traits" + ]; + + // Status is a login status of the user + LoginStatus Status = 6 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "status,omitempty" ]; + + // Expires if set sets TTL on the user + google.protobuf.Timestamp Expires = 7 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "expires" + ]; + + // CreatedBy holds information about agent or person created this user + CreatedBy CreatedBy = 8 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "created_by,omitempty" ]; + + // LocalAuths hold sensitive data necessary for performing local + // authentication + LocalAuthSecrets LocalAuth = 9 [ (gogoproto.jsontag) = "local_auth,omitempty" ]; } // ExternalIdentity is OpenID Connect/SAML or Github identity that is linked @@ -591,23 +750,31 @@ message ExternalIdentity { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; - // ConnectorID is id of registered OIDC connector, e.g. 'google-example.com' - string ConnectorID = 1 [(gogoproto.jsontag) = "connector_id,omitempty"]; + // ConnectorID is id of registered OIDC connector, e.g. 'google-example.com' + string ConnectorID = 1 [ (gogoproto.jsontag) = "connector_id,omitempty" ]; - // Username is username supplied by external identity provider - string Username = 2 [(gogoproto.jsontag) = "username,omitempty"]; + // Username is username supplied by external identity provider + string Username = 2 [ (gogoproto.jsontag) = "username,omitempty" ]; } // LoginStatus is a login status of the user message LoginStatus { - // IsLocked tells us if user is locked - bool IsLocked = 1 [(gogoproto.jsontag) = "is_locked"]; - // LockedMessage contains the message in case if user is locked - string LockedMessage = 2 [(gogoproto.jsontag) = "locked_message,omitempty"]; - // LockedTime contains time when user was locked - google.protobuf.Timestamp LockedTime = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "locked_time,omitempty"]; - // LockExpires contains time when this lock will expire - google.protobuf.Timestamp LockExpires = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "lock_expires,omitempty"]; + // IsLocked tells us if user is locked + bool IsLocked = 1 [ (gogoproto.jsontag) = "is_locked" ]; + // LockedMessage contains the message in case if user is locked + string LockedMessage = 2 [ (gogoproto.jsontag) = "locked_message,omitempty" ]; + // LockedTime contains time when user was locked + google.protobuf.Timestamp LockedTime = 3 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "locked_time,omitempty" + ]; + // LockExpires contains time when this lock will expire + google.protobuf.Timestamp LockExpires = 4 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "lock_expires,omitempty" + ]; } // CreatedBy holds information about the person or agent who created the user @@ -615,107 +782,114 @@ message CreatedBy { option (gogoproto.goproto_stringer) = false; option (gogoproto.stringer) = false; - // Identity if present means that user was automatically created by identity - ConnectorRef Connector = 1 [(gogoproto.nullable) = true, (gogoproto.jsontag) = "connector,omitempty"]; - // Time specifies when user was created - google.protobuf.Timestamp Time = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "time"]; - // User holds information about user - UserRef User = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "user"]; + // Identity if present means that user was automatically created by identity + ConnectorRef Connector = 1 + [ (gogoproto.nullable) = true, (gogoproto.jsontag) = "connector,omitempty" ]; + // Time specifies when user was created + google.protobuf.Timestamp Time = 2 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "time" ]; + // User holds information about user + UserRef User = 3 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "user" ]; } // U2FRegistrationData encodes the universal second factor registration payload. message U2FRegistrationData { // Raw is the serialized registration data as received from the token - bytes Raw = 1 [(gogoproto.jsontag) = "raw"]; + bytes Raw = 1 [ (gogoproto.jsontag) = "raw" ]; // KeyHandle uniquely identifies a key on a device - bytes KeyHandle = 2 [(gogoproto.jsontag) = "key_handle"]; + bytes KeyHandle = 2 [ (gogoproto.jsontag) = "key_handle" ]; // PubKey is an DER encoded ecdsa public key - bytes PubKey = 3 [(gogoproto.jsontag) = "pubkey"]; + bytes PubKey = 3 [ (gogoproto.jsontag) = "pubkey" ]; } // LocalAuthSecrets holds sensitive data used to authenticate a local user. message LocalAuthSecrets { // PasswordHash encodes a combined salt & hash for password verification. - bytes PasswordHash = 1 [(gogoproto.jsontag) = "password_hash,omitempty"]; + bytes PasswordHash = 1 [ (gogoproto.jsontag) = "password_hash,omitempty" ]; // TOTPKey is the key used for Time-based One Time Password varification. - string TOTPKey = 2 [(gogoproto.jsontag) = "totp_key,omitempty"]; + string TOTPKey = 2 [ (gogoproto.jsontag) = "totp_key,omitempty" ]; // U2FRegistration holds Universal Second Factor registration info. - U2FRegistrationData U2FRegistration = 3 [(gogoproto.jsontag) = "u2f_registration,omitempty"]; + U2FRegistrationData U2FRegistration = 3 [ (gogoproto.jsontag) = "u2f_registration,omitempty" ]; - // U2FCounter holds the highest seen Universal Second Factor registration count. - uint32 U2FCounter = 4 [(gogoproto.jsontag) = "u2f_counter,omitempty"]; + // U2FCounter holds the highest seen Universal Second Factor registration + // count. + uint32 U2FCounter = 4 [ (gogoproto.jsontag) = "u2f_counter,omitempty" ]; } // ConnectorRef holds information about OIDC connector message ConnectorRef { - // Type is connector type - string Type = 1 [(gogoproto.jsontag) = "type"]; - // ID is connector ID - string ID = 2 [(gogoproto.jsontag) = "id"]; - // Identity is external identity of the user - string Identity = 3 [(gogoproto.jsontag) = "identity"]; + // Type is connector type + string Type = 1 [ (gogoproto.jsontag) = "type" ]; + // ID is connector ID + string ID = 2 [ (gogoproto.jsontag) = "id" ]; + // Identity is external identity of the user + string Identity = 3 [ (gogoproto.jsontag) = "identity" ]; } // UserRef holds references to user message UserRef { - // Name is name of the user - string Name = 1 [(gogoproto.jsontag) = "name"]; + // Name is name of the user + string Name = 1 [ (gogoproto.jsontag) = "name" ]; } // ReverseTunnelV2 is version 2 of the resource spec of the reverse tunnel message ReverseTunnelV2 { - // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; - // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is a resource metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; - // Spec is a reverse tunnel specification - ReverseTunnelSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + // Kind is a resource kind + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; + // SubKind is an optional resource sub kind, used in some resources + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is a resource metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; + // Spec is a reverse tunnel specification + ReverseTunnelSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // ReverseTunnelSpecV2 is a specification for V2 reverse tunnel message ReverseTunnelSpecV2 { - // ClusterName is a domain name of remote cluster we are connecting to - string ClusterName = 1 [(gogoproto.jsontag) = "cluster_name"]; - // DialAddrs is a list of remote address to establish a connection to - // it's always SSH over TCP - repeated string DialAddrs = 2 [(gogoproto.jsontag) = "dial_addrs,omitempty"]; - // Type is the type of reverse tunnel, either proxy or node. - string Type = 3 [(gogoproto.jsontag) = "type", (gogoproto.casttype) = "TunnelType"]; + // ClusterName is a domain name of remote cluster we are connecting to + string ClusterName = 1 [ (gogoproto.jsontag) = "cluster_name" ]; + // DialAddrs is a list of remote address to establish a connection to + // it's always SSH over TCP + repeated string DialAddrs = 2 [ (gogoproto.jsontag) = "dial_addrs,omitempty" ]; + // Type is the type of reverse tunnel, either proxy or node. + string Type = 3 [ (gogoproto.jsontag) = "type", (gogoproto.casttype) = "TunnelType" ]; } // TunnelConnectionV2 is version 2 of the resource spec of the tunnel connection message TunnelConnectionV2 { - option (gogoproto.goproto_stringer) = false; - option (gogoproto.stringer) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.stringer) = false; - // Kind is a resource kind - string Kind = 1 [(gogoproto.jsontag) = "kind"]; - // SubKind is an optional resource sub kind, used in some resources - string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"]; - // Version is version - string Version = 3 [(gogoproto.jsontag) = "version"]; - // Metadata is a resource metadata - Metadata Metadata = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata"]; - // Spec is a tunnel specification - TunnelConnectionSpecV2 Spec = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "spec"]; + // Kind is a resource kind + string Kind = 1 [ (gogoproto.jsontag) = "kind" ]; + // SubKind is an optional resource sub kind, used in some resources + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is a resource metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; + // Spec is a tunnel specification + TunnelConnectionSpecV2 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; } // TunnelConnectionSpecV2 is a specification for V2 tunnel connection message TunnelConnectionSpecV2 { - // ClusterName is a name of the cluster - string ClusterName = 1 [(gogoproto.jsontag) = "cluster_name"]; - // ProxyName is the name of the proxy server - string ProxyName = 2 [(gogoproto.jsontag) = "proxy_name"]; - // LastHeartbeat is a time of the last heartbeat - google.protobuf.Timestamp LastHeartbeat = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = "last_heartbeat,omitempty"]; - // Type is the type of reverse tunnel, either proxy or node. - string Type = 4 [(gogoproto.jsontag) = "type", (gogoproto.casttype) = "TunnelType"]; -} + // ClusterName is a name of the cluster + string ClusterName = 1 [ (gogoproto.jsontag) = "cluster_name" ]; + // ProxyName is the name of the proxy server + string ProxyName = 2 [ (gogoproto.jsontag) = "proxy_name" ]; + // LastHeartbeat is a time of the last heartbeat + google.protobuf.Timestamp LastHeartbeat = 3 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "last_heartbeat,omitempty" + ]; + // Type is the type of reverse tunnel, either proxy or node. + string Type = 4 [ (gogoproto.jsontag) = "type", (gogoproto.casttype) = "TunnelType" ]; +} \ No newline at end of file diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 6f9c8f1a1ea92..f30c952e4b617 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -20,6 +20,7 @@ package web import ( "compress/gzip" + "context" "crypto/subtle" "encoding/base64" "encoding/json" @@ -167,10 +168,10 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { h.DELETE("/webapi/sessions", h.WithAuth(h.deleteSession)) h.POST("/webapi/sessions/renew", h.WithAuth(h.renewSession)) - // Users - h.GET("/webapi/users/invites/:token", httplib.MakeHandler(h.renderUserInvite)) - h.POST("/webapi/users", httplib.MakeHandler(h.createNewUser)) + h.GET("/webapi/users/password/token/:token", httplib.MakeHandler(h.getResetPasswordTokenHandle)) + h.PUT("/webapi/users/password/token", httplib.WithCSRFProtection(h.changePasswordWithToken)) h.PUT("/webapi/users/password", h.WithAuth(h.changePassword)) + h.POST("/webapi/sites/:site/namespaces/:namespace/users/password/token", h.WithClusterAuth(h.createResetPasswordToken)) // Issues SSH temp certificates based on 2FA access creds h.POST("/webapi/ssh/certs", httplib.MakeHandler(h.createSSHCert)) @@ -222,7 +223,6 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { // U2F related APIs h.GET("/webapi/u2f/signuptokens/:token", httplib.MakeHandler(h.u2fRegisterRequest)) - h.POST("/webapi/u2f/users", httplib.MakeHandler(h.createNewU2FUser)) h.POST("/webapi/u2f/password/changerequest", h.WithAuth(h.u2fChangePasswordRequest)) h.POST("/webapi/u2f/signrequest", httplib.MakeHandler(h.u2fSignRequest)) h.POST("/webapi/u2f/sessions", httplib.MakeHandler(h.createSessionWithU2FSignResponse)) @@ -1027,19 +1027,6 @@ type CreateSessionResponse struct { ExpiresIn int `json:"expires_in"` } -type createSessionResponseRaw struct { - // Type is token type (bearer) - Type string `json:"type"` - // Token value - Token string `json:"token"` - // ExpiresIn sets seconds before this token is not valid - ExpiresIn int `json:"expires_in"` -} - -func (r createSessionResponseRaw) response() (*CreateSessionResponse, error) { - return &CreateSessionResponse{Type: r.Type, Token: r.Token, ExpiresIn: r.ExpiresIn}, nil -} - func NewSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) { clt, err := ctx.GetClient() if err != nil { @@ -1177,32 +1164,85 @@ func (h *Handler) renewSession(w http.ResponseWriter, r *http.Request, _ httprou return NewSessionResponse(newContext) } -type renderUserInviteResponse struct { - InviteToken string `json:"invite_token"` - User string `json:"user"` - QR []byte `json:"qr"` +func (h *Handler) changePasswordWithToken(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { + var req auth.ChangePasswordWithTokenRequest + if err := httplib.ReadJSON(r, &req); err != nil { + return nil, trace.Wrap(err) + } + + sess, err := h.auth.proxyClient.ChangePasswordWithToken(r.Context(), req) + if err != nil { + return nil, trace.Wrap(err) + } + ctx, err := h.auth.ValidateSession(sess.GetUser(), sess.GetName()) + if err != nil { + return nil, trace.Wrap(err) + } + if err := SetSession(w, sess.GetUser(), sess.GetName()); err != nil { + return nil, trace.Wrap(err) + } + + return NewSessionResponse(ctx) +} + +func (h *Handler) createResetPasswordToken(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { + clt, err := ctx.GetUserClient(site) + if err != nil { + return nil, trace.Wrap(err) + } + + var req auth.CreateResetPasswordTokenRequest + if err := httplib.ReadJSON(r, &req); err != nil { + return nil, trace.Wrap(err) + } + + token, err := clt.CreateResetPasswordToken(context.TODO(), + auth.CreateResetPasswordTokenRequest{ + Name: req.Name, + Type: req.Type, + }) + + if err != nil { + return nil, trace.Wrap(err) + } + + return ui.ResetPasswordToken{ + URL: token.GetURL(), + Expiry: token.Expiry(), + }, nil } -// renderUserInvite is called to show user the new user invitation page -// -// GET /v1/webapi/users/invites/:token -// -// Response: -// -// {"invite_token": "token", "user": "alex", qr: "base64-encoded-qr-code image"} -// -// -func (h *Handler) renderUserInvite(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - token := p[0].Value - user, qrCodeBytes, err := h.auth.GetUserInviteInfo(token) +func (h *Handler) getResetPasswordTokenHandle(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { + result, err := h.getResetPasswordToken(context.TODO(), p.ByName("token")) + if err != nil { + log.Warnf("Failed to fetch a reset password token: %v.", err) + // We hide the error from the remote user to avoid giving any hints. + return nil, trace.AccessDenied("bad or expired token") + } + + return result, nil +} + +func (h *Handler) getResetPasswordToken(ctx context.Context, tokenID string) (interface{}, error) { + token, err := h.auth.proxyClient.GetResetPasswordToken(ctx, tokenID) + if err != nil { + return nil, trace.Wrap(err) + } + + // RotateResetPasswordTokenSecrets rotates secrets for a given tokenID. + // It gets called every time a user fetches 2nd-factor secrets during registration attempt. + // This ensures that an attacker that gains the ResetPasswordToken link can not view it, + // extract the OTP key from the QR code, then allow the user to signup with + // the same OTP token. + secrets, err := h.auth.proxyClient.RotateResetPasswordTokenSecrets(ctx, tokenID) if err != nil { return nil, trace.Wrap(err) } - return &renderUserInviteResponse{ - InviteToken: token, - User: user, - QR: qrCodeBytes, + return ui.ResetPasswordToken{ + TokenID: token.GetName(), + User: token.GetUser(), + QRCode: secrets.GetQRCode(), }, nil } @@ -1215,7 +1255,7 @@ func (h *Handler) renderUserInvite(w http.ResponseWriter, r *http.Request, p htt // {"version":"U2F_V2","challenge":"randombase64string","appId":"https://mycorp.com:3080"} // func (h *Handler) u2fRegisterRequest(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - token := p[0].Value + token := p.ByName("token") u2fRegisterRequest, err := h.auth.GetUserInviteU2FRegisterRequest(token) if err != nil { return nil, trace.Wrap(err) @@ -1283,76 +1323,6 @@ func (h *Handler) createSessionWithU2FSignResponse(w http.ResponseWriter, r *htt return NewSessionResponse(ctx) } -// createNewUser req is a request to create a new Teleport user -type createNewUserReq struct { - InviteToken string `json:"invite_token"` - Pass string `json:"pass"` - SecondFactorToken string `json:"second_factor_token,omitempty"` -} - -// createNewUser creates new user entry based on the invite token -// -// POST /v1/webapi/users -// -// {"invite_token": "unique invite token", "pass": "user password", "second_factor_token": "valid second factor token"} -// -// Successful response: (session cookie is set) -// -// {"type": "bearer", "token": "bearer token", "user": "alex", "expires_in": 20} -func (h *Handler) createNewUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - var req *createNewUserReq - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - sess, err := h.auth.CreateNewUser(req.InviteToken, req.Pass, req.SecondFactorToken) - if err != nil { - return nil, trace.Wrap(err) - } - ctx, err := h.auth.ValidateSession(sess.GetUser(), sess.GetName()) - if err != nil { - return nil, trace.Wrap(err) - } - if err := SetSession(w, sess.GetUser(), sess.GetName()); err != nil { - return nil, trace.Wrap(err) - } - return NewSessionResponse(ctx) -} - -// 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"` - U2FRegisterResponse u2f.RegisterResponse `json:"u2f_register_response"` -} - -// createNewU2FUser creates a new user configured to use U2F as the second factor -// -// POST /webapi/u2f/users -// -// {"invite_token": "unique invite token", "pass": "user password", "u2f_register_response": {"registrationData":"verylongbase64string","clientData":"longbase64string"}} -// -// Successful response: (session cookie is set) -// -// {"type": "bearer", "token": "bearer token", "user": "alex", "expires_in": 20} -func (h *Handler) createNewU2FUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - var req *createNewU2FUserReq - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - sess, err := h.auth.CreateNewU2FUser(req.InviteToken, req.Pass, req.U2FRegisterResponse) - if err != nil { - return nil, trace.Wrap(err) - } - ctx, err := h.auth.ValidateSession(sess.GetUser(), sess.GetName()) - if err != nil { - return nil, trace.Wrap(err) - } - if err := SetSession(w, sess.GetUser(), sess.GetName()); err != nil { - return nil, trace.Wrap(err) - } - return NewSessionResponse(ctx) -} - // getClusters returns a list of clusters // // GET /v1/webapi/sites diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index bb293eec970e2..e4c544df8cfc8 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -276,7 +276,7 @@ type authPack struct { } func (s *WebSuite) authPackFromResponse(c *C, re *roundtrip.Response) *authPack { - var sess *createSessionResponseRaw + var sess *CreateSessionResponse c.Assert(json.Unmarshal(re.Bytes(), &sess), IsNil) jar, err := cookiejar.New(nil) @@ -332,7 +332,7 @@ func (s *WebSuite) authPack(c *C, user string) *authPack { re, err := s.login(clt, csrfToken, csrfToken, req) c.Assert(err, IsNil) - var rawSess *createSessionResponseRaw + var rawSess *CreateSessionResponse c.Assert(json.Unmarshal(re.Bytes(), &rawSess), IsNil) sess, err := rawSess.response() @@ -376,83 +376,6 @@ func (s *WebSuite) createUser(c *C, user string, login string, pass string, otpS c.Assert(err, IsNil) } -func (s *WebSuite) TestNewUser(c *C) { - token, err := s.server.Auth().CreateSignupToken(services.UserV1{Name: "bob", AllowedLogins: []string{s.user}}, 0) - c.Assert(err, IsNil) - - // Save the original signup token, after GET /v2/webapi/users/invites/ - // this should change. - ost, err := s.server.Auth().GetSignupToken(token) - c.Assert(err, IsNil) - - tokens, err := s.server.Auth().GetTokens() - c.Assert(err, IsNil) - c.Assert(len(tokens), Equals, 1) - c.Assert(tokens[0].GetName(), Equals, token) - - clt := s.client() - re, err := clt.Get(context.Background(), clt.Endpoint("webapi", "users", "invites", token), url.Values{}) - c.Assert(err, IsNil) - - var out *renderUserInviteResponse - c.Assert(json.Unmarshal(re.Bytes(), &out), IsNil) - c.Assert(out.User, Equals, "bob") - c.Assert(out.InviteToken, Equals, token) - - st, err := s.server.Auth().GetSignupToken(token) - c.Assert(err, IsNil) - - // Make sure that the signup token changed after rending the endpoint - // GET /v2/webapi/users/invites/ above. - c.Assert(st, Not(Equals), ost) - - validToken, err := totp.GenerateCode(st.OTPKey, time.Now()) - c.Assert(err, IsNil) - - tempPass := "abc123" - - re, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "users"), createNewUserReq{ - InviteToken: token, - Pass: tempPass, - SecondFactorToken: validToken, - }) - c.Assert(err, IsNil) - - var rawSess *createSessionResponseRaw - c.Assert(json.Unmarshal(re.Bytes(), &rawSess), IsNil) - cookies := re.Cookies() - c.Assert(len(cookies), Equals, 1) - - // now make sure we are logged in by calling authenticated method - // we need to supply both session cookie and bearer token for - // request to succeed - jar, err := cookiejar.New(nil) - c.Assert(err, IsNil) - - clt = s.client(roundtrip.BearerAuth(rawSess.Token), roundtrip.CookieJar(jar)) - jar.SetCookies(s.url(), re.Cookies()) - - re, err = clt.Get(context.Background(), clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, IsNil) - - var clusters *ui.AvailableClusters - c.Assert(json.Unmarshal(re.Bytes(), &clusters), IsNil) - - // in absence of session cookie or bearer auth the same request fill fail - - // no session cookie: - clt = s.client(roundtrip.BearerAuth(rawSess.Token)) - re, err = clt.Get(context.Background(), clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, NotNil) - c.Assert(trace.IsAccessDenied(err), Equals, true) - - // no bearer token: - clt = s.client(roundtrip.CookieJar(jar)) - re, err = clt.Get(context.Background(), clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, NotNil) - c.Assert(trace.IsAccessDenied(err), Equals, true) -} - func (s *WebSuite) TestSAMLSuccess(c *C) { input := fixtures.SAMLOktaConnectorV2 @@ -559,7 +482,7 @@ func (s *WebSuite) TestWebSessionsCRUD(c *C) { re, err := pack.clt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) c.Assert(err, IsNil) - var clusters *ui.AvailableClusters + var clusters []ui.Cluster c.Assert(json.Unmarshal(re.Bytes(), &clusters), IsNil) // now delete session @@ -1153,43 +1076,37 @@ func (s *WebSuite) TestPlayback(c *C) { defer ws.Close() } -func (s *WebSuite) TestNewU2FUser(c *C) { - // configure cluster authentication preferences - cap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ +func (s *WebSuite) TestLogin(c *C) { + ap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ Type: teleport.Local, - SecondFactor: teleport.U2F, - U2F: &services.U2F{ - AppID: "https://" + s.server.ClusterName(), - Facets: []string{"https://" + s.server.ClusterName()}, - }, + SecondFactor: teleport.OFF, }) c.Assert(err, IsNil) - err = s.server.AuthServer.AuthServer.SetAuthPreference(cap) - c.Assert(err, IsNil) - - token, err := s.server.Auth().CreateSignupToken(services.UserV1{Name: "bob", AllowedLogins: []string{s.user}}, 0) + err = s.server.Auth().SetAuthPreference(ap) c.Assert(err, IsNil) - clt := s.client() - re, err := clt.Get(context.Background(), clt.Endpoint("webapi", "u2f", "signuptokens", token), url.Values{}) - c.Assert(err, IsNil) + // create user + s.createUser(c, "user1", "root", "password", "") - var u2fRegReq u2f.RegisterRequest - c.Assert(json.Unmarshal(re.Bytes(), &u2fRegReq), IsNil) + loginReq, err := json.Marshal(createSessionReq{ + User: "user1", + Pass: "password", + }) - u2fRegResp, err := s.mockU2F.RegisterResponse(&u2fRegReq) + clt := s.client() + req, err := http.NewRequest("POST", clt.Endpoint("webapi", "sessions"), bytes.NewBuffer(loginReq)) c.Assert(err, IsNil) - tempPass := "abc123" + csrfToken := "2ebcb768d0090ea4368e42880c970b61865c326172a4a2343b645cf5d7f20992" + addCSRFCookieToReq(req, csrfToken) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(csrf.HeaderName, csrfToken) - re, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "u2f", "users"), createNewU2FUserReq{ - InviteToken: token, - Pass: tempPass, - U2FRegisterResponse: *u2fRegResp, + re, err := clt.Client.RoundTrip(func() (*http.Response, error) { + return clt.Client.HTTPClient().Do(req) }) - c.Assert(err, IsNil) - var rawSess *createSessionResponseRaw + var rawSess *CreateSessionResponse c.Assert(json.Unmarshal(re.Bytes(), &rawSess), IsNil) cookies := re.Cookies() c.Assert(len(cookies), Equals, 1) @@ -1206,7 +1123,7 @@ func (s *WebSuite) TestNewU2FUser(c *C) { re, err = clt.Get(context.Background(), clt.Endpoint("webapi", "sites"), url.Values{}) c.Assert(err, IsNil) - var clusters *ui.AvailableClusters + var clusters []ui.Cluster c.Assert(json.Unmarshal(re.Bytes(), &clusters), IsNil) // in absence of session cookie or bearer auth the same request fill fail @@ -1224,6 +1141,116 @@ func (s *WebSuite) TestNewU2FUser(c *C) { c.Assert(trace.IsAccessDenied(err), Equals, true) } +func (s *WebSuite) TestChangePasswordWithTokenOTP(c *C) { + ap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OTP, + }) + c.Assert(err, IsNil) + err = s.server.Auth().SetAuthPreference(ap) + c.Assert(err, IsNil) + + // create user + s.createUser(c, "user1", "root", "password", "") + + // create password change token + token, err := s.server.Auth().CreateResetPasswordToken(context.TODO(), auth.CreateResetPasswordTokenRequest{ + Name: "user1", + }) + c.Assert(err, IsNil) + + clt := s.client() + re, err := clt.Get(context.Background(), clt.Endpoint("webapi", "users", "password", "token", token.GetName()), url.Values{}) + c.Assert(err, IsNil) + + var uiToken *ui.ResetPasswordToken + c.Assert(json.Unmarshal(re.Bytes(), &uiToken), IsNil) + c.Assert(uiToken.User, Equals, token.GetUser()) + c.Assert(uiToken.TokenID, Equals, token.GetName()) + + secrets, err := s.server.Auth().RotateResetPasswordTokenSecrets(context.TODO(), token.GetName()) + c.Assert(err, IsNil) + + secondFactorToken, err := totp.GenerateCode(secrets.GetOTPKey(), time.Now()) + c.Assert(err, IsNil) + + data, err := json.Marshal(auth.ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + Password: []byte("abc123"), + SecondFactorToken: secondFactorToken, + }) + + req, err := http.NewRequest("PUT", clt.Endpoint("webapi", "users", "password", "token"), bytes.NewBuffer(data)) + c.Assert(err, IsNil) + + csrfToken := "2ebcb768d0090ea4368e42880c970b61865c326172a4a2343b645cf5d7f20992" + addCSRFCookieToReq(req, csrfToken) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(csrf.HeaderName, csrfToken) + + re, err = clt.Client.RoundTrip(func() (*http.Response, error) { + return clt.Client.HTTPClient().Do(req) + }) + + var rawSess *CreateSessionResponse + c.Assert(json.Unmarshal(re.Bytes(), &rawSess), IsNil) + c.Assert(rawSess.Token != "", Equals, true) +} + +func (s *WebSuite) TestChangePasswordWithTokenU2F(c *C) { + ap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.U2F, + U2F: &services.U2F{ + AppID: "https://" + s.server.ClusterName(), + Facets: []string{"https://" + s.server.ClusterName()}, + }, + }) + c.Assert(err, IsNil) + err = s.server.Auth().SetAuthPreference(ap) + c.Assert(err, IsNil) + + s.createUser(c, "user2", "root", "password", "") + + // create reset password token + token, err := s.server.Auth().CreateResetPasswordToken(context.TODO(), auth.CreateResetPasswordTokenRequest{ + Name: "user2", + }) + c.Assert(err, IsNil) + + clt := s.client() + re, err := clt.Get(context.Background(), clt.Endpoint("webapi", "u2f", "signuptokens", token.GetName()), url.Values{}) + c.Assert(err, IsNil) + + var u2fRegReq u2f.RegisterRequest + c.Assert(json.Unmarshal(re.Bytes(), &u2fRegReq), IsNil) + + u2fRegResp, err := s.mockU2F.RegisterResponse(&u2fRegReq) + c.Assert(err, IsNil) + + data, err := json.Marshal(auth.ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + Password: []byte("qweQWE"), + U2FRegisterResponse: *u2fRegResp, + }) + + req, err := http.NewRequest("PUT", clt.Endpoint("webapi", "users", "password", "token"), bytes.NewBuffer(data)) + c.Assert(err, IsNil) + + csrfToken := "2ebcb768d0090ea4368e42880c970b61865c326172a4a2343b645cf5d7f20992" + addCSRFCookieToReq(req, csrfToken) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(csrf.HeaderName, csrfToken) + + re, err = clt.Client.RoundTrip(func() (*http.Response, error) { + return clt.Client.HTTPClient().Do(req) + }) + + var rawSess *CreateSessionResponse + c.Assert(json.Unmarshal(re.Bytes(), &rawSess), IsNil) + c.Assert(rawSess.Token != "", Equals, true) +} + func (s *WebSuite) TestU2FLogin(c *C) { // configure cluster authentication preferences cap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ @@ -1238,25 +1265,34 @@ func (s *WebSuite) TestU2FLogin(c *C) { err = s.server.Auth().SetAuthPreference(cap) c.Assert(err, IsNil) - token, err := s.server.Auth().CreateSignupToken(services.UserV1{Name: "bob", AllowedLogins: []string{s.user}}, 0) + // create user + s.createUser(c, "bob", "root", "password", "") + + // create password change token + token, err := s.server.Auth().CreateResetPasswordToken(context.TODO(), auth.CreateResetPasswordTokenRequest{ + Name: "bob", + }) c.Assert(err, IsNil) - u2fRegReq, err := s.proxyClient.GetSignupU2FRegisterRequest(token) + u2fRegReq, err := s.proxyClient.GetSignupU2FRegisterRequest(token.GetName()) c.Assert(err, IsNil) u2fRegResp, err := s.mockU2F.RegisterResponse(u2fRegReq) c.Assert(err, IsNil) - tempPass := "abc123" - - _, err = s.proxyClient.CreateUserWithU2FToken(token, tempPass, *u2fRegResp) + tempPass := []byte("abc123") + _, err = s.proxyClient.ChangePasswordWithToken(context.TODO(), auth.ChangePasswordWithTokenRequest{ + TokenID: token.GetName(), + U2FRegisterResponse: *u2fRegResp, + Password: tempPass, + }) c.Assert(err, IsNil) // normal login clt := s.client() re, err := clt.PostJSON(context.Background(), clt.Endpoint("webapi", "u2f", "signrequest"), client.U2fSignRequestReq{ User: "bob", - Pass: tempPass, + Pass: string(tempPass), }) c.Assert(err, IsNil) var u2fSignReq u2f.SignRequest @@ -1272,10 +1308,9 @@ func (s *WebSuite) TestU2FLogin(c *C) { c.Assert(err, IsNil) // bad login: corrupted sign responses, should fail - re, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "u2f", "signrequest"), client.U2fSignRequestReq{ User: "bob", - Pass: tempPass, + Pass: string(tempPass), }) c.Assert(err, IsNil) c.Assert(json.Unmarshal(re.Bytes(), &u2fSignReq), IsNil) @@ -1286,7 +1321,6 @@ func (s *WebSuite) TestU2FLogin(c *C) { // corrupted KeyHandle u2fSignRespCopy := u2fSignResp u2fSignRespCopy.KeyHandle = u2fSignRespCopy.KeyHandle + u2fSignRespCopy.KeyHandle - _, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "u2f", "sessions"), u2fSignResponseReq{ User: "bob", U2FSignResponse: *u2fSignRespCopy, @@ -1314,12 +1348,10 @@ func (s *WebSuite) TestU2FLogin(c *C) { c.Assert(err, NotNil) // bad login: counter not increasing, should fail - s.mockU2F.SetCounter(0) - re, err = clt.PostJSON(context.Background(), clt.Endpoint("webapi", "u2f", "signrequest"), client.U2fSignRequestReq{ User: "bob", - Pass: tempPass, + Pass: string(tempPass), }) c.Assert(err, IsNil) c.Assert(json.Unmarshal(re.Bytes(), &u2fSignReq), IsNil) @@ -1819,3 +1851,7 @@ func newTerminalHandler() TerminalHandler { decoder: unicode.UTF8.NewDecoder(), } } + +func (r CreateSessionResponse) response() (*CreateSessionResponse, error) { + return &CreateSessionResponse{Type: r.Type, Token: r.Token, ExpiresIn: r.ExpiresIn}, nil +} diff --git a/lib/web/sessions.go b/lib/web/sessions.go index dfeb1aecdd3f5..0217dca184044 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -29,7 +29,6 @@ import ( "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/reversetunnel" @@ -469,39 +468,10 @@ func (s *sessionCache) GetCertificateWithU2F(c client.CreateSSHCertWithU2FReq) ( }) } -func (s *sessionCache) GetUserInviteInfo(token string) (user string, otpQRCode []byte, err error) { - return s.proxyClient.GetSignupTokenData(token) -} - func (s *sessionCache) GetUserInviteU2FRegisterRequest(token string) (*u2f.RegisterRequest, error) { return s.proxyClient.GetSignupU2FRegisterRequest(token) } -func (s *sessionCache) CreateNewUser(token, password, otpToken string) (services.WebSession, error) { - cap, err := s.proxyClient.GetAuthPreference() - if err != nil { - return nil, trace.Wrap(err) - } - - var webSession services.WebSession - - switch cap.GetSecondFactor() { - case teleport.OFF: - webSession, err = s.proxyClient.CreateUserWithoutOTP(token, password) - case teleport.OTP, teleport.TOTP, teleport.HOTP: - webSession, err = s.proxyClient.CreateUserWithOTP(token, password, otpToken) - } - if err != nil { - return nil, trace.Wrap(err) - } - - return webSession, nil -} - -func (s *sessionCache) CreateNewU2FUser(token string, password string, u2fRegisterResponse u2f.RegisterResponse) (services.WebSession, error) { - return s.proxyClient.CreateUserWithU2FToken(token, password, u2fRegisterResponse) -} - func (s *sessionCache) ValidateTrustedCluster(validateRequest *auth.ValidateTrustedClusterRequest) (*auth.ValidateTrustedClusterResponse, error) { return s.proxyClient.ValidateTrustedCluster(validateRequest) } diff --git a/lib/web/ui/resetpasswordtoken.go b/lib/web/ui/resetpasswordtoken.go new file mode 100644 index 0000000000000..7ba3fced551bf --- /dev/null +++ b/lib/web/ui/resetpasswordtoken.go @@ -0,0 +1,33 @@ +/* +Copyright 2020 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 ui + +import "time" + +// ResetPasswordToken describes ResetPasswordToken UI object +type ResetPasswordToken struct { + // TokenID is token ID + TokenID string `json:"tokenId"` + // User is user name associated with this token + User string `json:"user"` + // QRCode is a QR code value + QRCode []byte `json:"qrCode,omitempty"` + // URL is token URL + URL string `json:"url,omitempty"` + // Expiry is token expiration time + Expiry time.Time `json:"expiry,omitempty"` +} diff --git a/lib/wrappers/wrappers.pb.go b/lib/wrappers/wrappers.pb.go index 1f0e838fe99a0..89efb76a9d0f9 100644 --- a/lib/wrappers/wrappers.pb.go +++ b/lib/wrappers/wrappers.pb.go @@ -33,7 +33,7 @@ func (m *StringValues) Reset() { *m = StringValues{} } func (m *StringValues) String() string { return proto.CompactTextString(m) } func (*StringValues) ProtoMessage() {} func (*StringValues) Descriptor() ([]byte, []int) { - return fileDescriptor_wrappers_b4e6428cd870cf3a, []int{0} + return fileDescriptor_wrappers_27e842bc8bd4b60d, []int{0} } func (m *StringValues) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -76,7 +76,7 @@ func (m *LabelValues) Reset() { *m = LabelValues{} } func (m *LabelValues) String() string { return proto.CompactTextString(m) } func (*LabelValues) ProtoMessage() {} func (*LabelValues) Descriptor() ([]byte, []int) { - return fileDescriptor_wrappers_b4e6428cd870cf3a, []int{1} + return fileDescriptor_wrappers_27e842bc8bd4b60d, []int{1} } func (m *LabelValues) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -607,9 +607,9 @@ var ( ErrIntOverflowWrappers = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("wrappers.proto", fileDescriptor_wrappers_b4e6428cd870cf3a) } +func init() { proto.RegisterFile("wrappers.proto", fileDescriptor_wrappers_27e842bc8bd4b60d) } -var fileDescriptor_wrappers_b4e6428cd870cf3a = []byte{ +var fileDescriptor_wrappers_27e842bc8bd4b60d = []byte{ // 211 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0x2f, 0x4a, 0x2c, 0x28, 0x48, 0x2d, 0x2a, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0xf1, 0xa5, 0x44, diff --git a/lib/wrappers/wrappers.proto b/lib/wrappers/wrappers.proto index a784878043dea..e4abc8a0d1a7e 100644 --- a/lib/wrappers/wrappers.proto +++ b/lib/wrappers/wrappers.proto @@ -7,15 +7,13 @@ option (gogoproto.marshaler_all) = true; option (gogoproto.unmarshaler_all) = true; option (gogoproto.goproto_getters_all) = false; - // StringValues is a list of strings. -message StringValues { - repeated string Values = 1; -} +message StringValues { repeated string Values = 1; } // LabelValues is a list of key value pairs, where key is a string // and value is a list of string values. message LabelValues { // Values contains key value pairs. - map Values = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "labels"]; + map Values = 1 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "labels" ]; } diff --git a/tool/tctl/common/user_command.go b/tool/tctl/common/user_command.go index 3e5c7f96d765e..0d5b74bedf67f 100644 --- a/tool/tctl/common/user_command.go +++ b/tool/tctl/common/user_command.go @@ -17,8 +17,10 @@ limitations under the License. package common import ( + "context" "encoding/json" "fmt" + "net/url" "strings" "time" @@ -29,7 +31,6 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/service" "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/teleport/lib/web" "github.com/gravitational/trace" ) @@ -47,10 +48,11 @@ type UserCommand struct { // format is the output format, e.g. text or json format string - userAdd *kingpin.CmdClause - userUpdate *kingpin.CmdClause - userList *kingpin.CmdClause - userDelete *kingpin.CmdClause + userAdd *kingpin.CmdClause + userUpdate *kingpin.CmdClause + userList *kingpin.CmdClause + userDelete *kingpin.CmdClause + userChangePassword *kingpin.CmdClause } // Initialize allows UserCommand to plug itself into the CLI parser @@ -64,8 +66,8 @@ func (u *UserCommand) Initialize(app *kingpin.Application, config *service.Confi Default("").StringVar(&u.allowedLogins) u.userAdd.Flag("k8s-groups", "Kubernetes groups to assign to a user."). Default("").StringVar(&u.kubeGroups) - u.userAdd.Flag("ttl", fmt.Sprintf("Set expiration time for token, default is %v hour, maximum is %v hours", - int(defaults.SignupTokenTTL/time.Hour), int(defaults.MaxSignupTokenTTL/time.Hour))). + u.userAdd.Flag("ttl", fmt.Sprintf("Set expiration time for token, default is %v, maximum is %v", + defaults.SignupTokenTTL, defaults.MaxSignupTokenTTL)). Default(fmt.Sprintf("%v", defaults.SignupTokenTTL)).DurationVar(&u.ttl) u.userAdd.Flag("format", "Output format, 'text' or 'json'").Hidden().Default(teleport.Text).StringVar(&u.format) u.userAdd.Alias(AddUserHelp) @@ -81,6 +83,13 @@ func (u *UserCommand) Initialize(app *kingpin.Application, config *service.Confi u.userDelete = users.Command("rm", "Deletes user accounts").Alias("del") u.userDelete.Arg("logins", "Comma-separated list of user logins to delete"). Required().StringVar(&u.login) + + u.userChangePassword = users.Command("reset", "Reset user password and generate a new token") + u.userChangePassword.Arg("account", "Teleport user account name").Required().StringVar(&u.login) + u.userChangePassword.Flag("ttl", fmt.Sprintf("Set expiration time for token, default is %v, maximum is %v", + defaults.ChangePasswordTokenTTL, defaults.MaxChangePasswordTokenTTL)). + Default(fmt.Sprintf("%v", defaults.ChangePasswordTokenTTL)).DurationVar(&u.ttl) + u.userChangePassword.Flag("format", "Output format, 'text' or 'json'").Hidden().Default(teleport.Text).StringVar(&u.format) } // TryRun takes the CLI command as an argument (like "users add") and executes it. @@ -94,12 +103,45 @@ func (u *UserCommand) TryRun(cmd string, client auth.ClientI) (match bool, err e err = u.List(client) case u.userDelete.FullCommand(): err = u.Delete(client) + case u.userChangePassword.FullCommand(): + err = u.ChangePassword(client) default: return false, nil } return true, trace.Wrap(err) } +// ChangePassword resets user password and generates a token to setup new password +func (u *UserCommand) ChangePassword(client auth.ClientI) error { + req := auth.CreateResetPasswordTokenRequest{ + Name: u.login, + TTL: u.ttl, + Type: auth.ResetPasswordTokenTypePassword, + } + token, err := client.CreateResetPasswordToken(context.TODO(), req) + if err != nil { + return err + } + + url, err := url.Parse(token.GetURL()) + if err != nil { + return trace.Wrap(err) + } + + if u.format == teleport.Text { + ttl := token.Expiry().Sub(time.Now().UTC()).Round(time.Second) + fmt.Printf("Reset password token has been created and is valid for %v. Share this URL with the user to complete password reset process:\n%v\n\n", ttl, url) + fmt.Printf("NOTE: Make sure %v points at a Teleport proxy which users can access.\n", url.Host) + } else if u.format == teleport.JSON { + err = printTokenAsJSON(token) + if err != nil { + return trace.Wrap(err) + } + } + + return nil +} + // Add creates a new sign-up token and prints a token URL to stdout. // A user is not created until he visits the sign-up URL and completes the process func (u *UserCommand) Add(client auth.ClientI) error { @@ -111,35 +153,66 @@ func (u *UserCommand) Add(client auth.ClientI) error { if u.kubeGroups != "" { kubeGroups = strings.Split(u.kubeGroups, ",") } - user := services.UserV1{ - Name: u.login, - AllowedLogins: strings.Split(u.allowedLogins, ","), - KubeGroups: kubeGroups, + + // make sure that user does not exist + _, err := client.GetUser(u.login, false) + if err == nil { + if err == nil { + return trace.BadParameter("user(%v) already registered", u.login) + } } - token, err := client.CreateSignupToken(user, u.ttl) + + user, err := services.NewUser(u.login) + if err != nil { + return trace.Wrap(err) + } + + traits := map[string][]string{ + teleport.TraitLogins: strings.Split(u.allowedLogins, ","), + teleport.TraitKubeGroups: kubeGroups, + } + + user.SetTraits(traits) + user.AddRole(teleport.AdminRoleName) + err = client.UpsertUser(user) if err != nil { return err } - // try to auto-suggest the activation link - return u.PrintSignupURL(client, token, u.ttl, u.format) -} + token, err := client.CreateResetPasswordToken(context.TODO(), auth.CreateResetPasswordTokenRequest{ + Name: u.login, + TTL: u.ttl, + Type: auth.ResetPasswordTokenTypeInvite, + }) + if err != nil { + return err + } -// PrintSignupURL prints signup URL -func (u *UserCommand) PrintSignupURL(client auth.ClientI, token string, ttl time.Duration, format string) error { - signupURL, proxyHost := web.CreateSignupLink(client, token) + url, err := url.Parse(token.GetURL()) + if err != nil { + return trace.Wrap(err) + } - if format == teleport.Text { - fmt.Printf("Signup token has been created and is valid for %v hours. Share this URL with the user:\n%v\n\n", - int(ttl/time.Hour), signupURL) - fmt.Printf("NOTE: Make sure %v points at a Teleport proxy which users can access.\n", proxyHost) - } else { - out, err := json.MarshalIndent(services.NewInviteToken(token, signupURL, time.Now().Add(ttl).UTC()), "", " ") + if u.format == teleport.Text { + ttl := token.Expiry().Sub(time.Now().UTC()).Round(time.Second) + fmt.Printf("Invite token has been created and is valid for %v. Share this URL with the user to complete user setup:\n%v\n\n", ttl, url) + fmt.Printf("NOTE: Make sure %v points at a Teleport proxy which users can access.\n", url.Host) + } else if u.format == teleport.JSON { + err = printTokenAsJSON(token) if err != nil { - return trace.Wrap(err, "failed to marshal signup infos") + return trace.Wrap(err) } - fmt.Printf(string(out)) } + + return nil +} + +func printTokenAsJSON(token services.ResetPasswordToken) error { + out, err := json.MarshalIndent(token, "", " ") + if err != nil { + return trace.Wrap(err, "failed to marshal reset password token") + } + fmt.Printf(string(out)) return nil }