diff --git a/api/client/events.go b/api/client/events.go index d233a927202..743e38edec5 100644 --- a/api/client/events.go +++ b/api/client/events.go @@ -89,11 +89,21 @@ func EventToGRPC(in types.Event) (*proto.Event, error) { AccessRequest: r, } case *types.WebSessionV2: - if r.GetSubKind() != types.KindAppSession { - return nil, trace.BadParameter("only %v supported", types.KindAppSession) + switch r.GetSubKind() { + case types.KindAppSession: + out.Resource = &proto.Event_AppSession{ + AppSession: r, + } + case types.KindWebSession: + out.Resource = &proto.Event_WebSession{ + WebSession: r, + } + default: + return nil, trace.BadParameter("only %q supported", types.WebSessionSubKinds) } - out.Resource = &proto.Event_AppSession{ - AppSession: r, + case *types.WebTokenV3: + out.Resource = &proto.Event_WebToken{ + WebToken: r, } case *types.RemoteClusterV3: out.Resource = &proto.Event_RemoteCluster{ @@ -176,6 +186,12 @@ func EventFromGRPC(in proto.Event) (*types.Event, error) { } else if r := in.GetAppSession(); r != nil { out.Resource = r return &out, nil + } else if r := in.GetWebSession(); r != nil { + out.Resource = r + return &out, nil + } else if r := in.GetWebToken(); r != nil { + out.Resource = r + return &out, nil } else if r := in.GetRemoteCluster(); r != nil { out.Resource = r return &out, nil diff --git a/api/client/proto/authservice.pb.go b/api/client/proto/authservice.pb.go index af62cf7b9f0..65ad2d2e242 100644 --- a/api/client/proto/authservice.pb.go +++ b/api/client/proto/authservice.pb.go @@ -63,7 +63,7 @@ func (x Operation) String() string { return proto.EnumName(Operation_name, int32(x)) } func (Operation) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{0} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{0} } type AddMFADeviceRequestInit_DeviceType int32 @@ -86,7 +86,7 @@ func (x AddMFADeviceRequestInit_DeviceType) String() string { return proto.EnumName(AddMFADeviceRequestInit_DeviceType_name, int32(x)) } func (AddMFADeviceRequestInit_DeviceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{66, 0} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{70, 0} } // Event returns cluster event @@ -112,6 +112,8 @@ type Event struct { // *Event_AppSession // *Event_RemoteCluster // *Event_DatabaseServer + // *Event_WebSession + // *Event_WebToken Resource isEvent_Resource `protobuf_oneof:"Resource"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -122,7 +124,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_authservice_a2d5604285d9f75d, []int{0} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{0} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -205,6 +207,12 @@ type Event_RemoteCluster struct { type Event_DatabaseServer struct { DatabaseServer *types.DatabaseServerV3 `protobuf:"bytes,17,opt,name=DatabaseServer,oneof"` } +type Event_WebSession struct { + WebSession *types.WebSessionV2 `protobuf:"bytes,18,opt,name=WebSession,oneof"` +} +type Event_WebToken struct { + WebToken *types.WebTokenV3 `protobuf:"bytes,19,opt,name=WebToken,oneof"` +} func (*Event_ResourceHeader) isEvent_Resource() {} func (*Event_CertAuthority) isEvent_Resource() {} @@ -222,6 +230,8 @@ func (*Event_AccessRequest) isEvent_Resource() {} func (*Event_AppSession) isEvent_Resource() {} func (*Event_RemoteCluster) isEvent_Resource() {} func (*Event_DatabaseServer) isEvent_Resource() {} +func (*Event_WebSession) isEvent_Resource() {} +func (*Event_WebToken) isEvent_Resource() {} func (m *Event) GetResource() isEvent_Resource { if m != nil { @@ -349,6 +359,20 @@ func (m *Event) GetDatabaseServer() *types.DatabaseServerV3 { return nil } +func (m *Event) GetWebSession() *types.WebSessionV2 { + if x, ok := m.GetResource().(*Event_WebSession); ok { + return x.WebSession + } + return nil +} + +func (m *Event) GetWebToken() *types.WebTokenV3 { + if x, ok := m.GetResource().(*Event_WebToken); ok { + return x.WebToken + } + return nil +} + // XXX_OneofFuncs is for the internal use of the proto package. func (*Event) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { return _Event_OneofMarshaler, _Event_OneofUnmarshaler, _Event_OneofSizer, []interface{}{ @@ -368,6 +392,8 @@ func (*Event) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, (*Event_AppSession)(nil), (*Event_RemoteCluster)(nil), (*Event_DatabaseServer)(nil), + (*Event_WebSession)(nil), + (*Event_WebToken)(nil), } } @@ -455,6 +481,16 @@ func _Event_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { if err := b.EncodeMessage(x.DatabaseServer); err != nil { return err } + case *Event_WebSession: + _ = b.EncodeVarint(18<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.WebSession); err != nil { + return err + } + case *Event_WebToken: + _ = b.EncodeVarint(19<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.WebToken); err != nil { + return err + } case nil: default: return fmt.Errorf("Event.Resource has unexpected type %T", x) @@ -593,6 +629,22 @@ func _Event_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) err := b.DecodeMessage(msg) m.Resource = &Event_DatabaseServer{msg} return true, err + case 18: // Resource.WebSession + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(types.WebSessionV2) + err := b.DecodeMessage(msg) + m.Resource = &Event_WebSession{msg} + return true, err + case 19: // Resource.WebToken + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(types.WebTokenV3) + err := b.DecodeMessage(msg) + m.Resource = &Event_WebToken{msg} + return true, err default: return false, nil } @@ -682,6 +734,16 @@ func _Event_OneofSizer(msg proto.Message) (n int) { n += 2 // tag and wire n += proto.SizeVarint(uint64(s)) n += s + case *Event_WebSession: + s := proto.Size(x.WebSession) + n += 2 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Event_WebToken: + s := proto.Size(x.WebToken) + n += 2 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s case nil: default: panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) @@ -702,7 +764,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_authservice_a2d5604285d9f75d, []int{1} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{1} } func (m *Watch) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -750,17 +812,19 @@ type WatchKind struct { Name string `protobuf:"bytes,3,opt,name=Name,proto3" json:"name"` // Filter is an optional mapping of custom filter parameters. // Valid values vary by resource kind. - Filter map[string]string `protobuf:"bytes,4,rep,name=Filter" json:"filter,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Filter map[string]string `protobuf:"bytes,4,rep,name=Filter" json:"filter,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // SubKind is a resource subkind to watch + SubKind string `protobuf:"bytes,5,opt,name=SubKind,proto3" json:"sub_kind,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } 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_authservice_a2d5604285d9f75d, []int{2} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{2} } func (m *WatchKind) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -817,6 +881,13 @@ func (m *WatchKind) GetFilter() map[string]string { return nil } +func (m *WatchKind) GetSubKind() string { + if m != nil { + return m.SubKind + } + return "" +} + // Set of certificates corresponding to a single public key. type Certs struct { // SSH X509 cert (PEM-encoded). @@ -832,7 +903,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_authservice_a2d5604285d9f75d, []int{3} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{3} } func (m *Certs) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -912,7 +983,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_authservice_a2d5604285d9f75d, []int{4} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{4} } func (m *UserCertsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1016,7 +1087,7 @@ func (m *RouteToDatabase) Reset() { *m = RouteToDatabase{} } func (m *RouteToDatabase) String() string { return proto.CompactTextString(m) } func (*RouteToDatabase) ProtoMessage() {} func (*RouteToDatabase) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{5} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{5} } func (m *RouteToDatabase) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1088,7 +1159,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_authservice_a2d5604285d9f75d, []int{6} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{6} } func (m *GetUserRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1144,7 +1215,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_authservice_a2d5604285d9f75d, []int{7} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{7} } func (m *GetUsersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1192,7 +1263,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_authservice_a2d5604285d9f75d, []int{8} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{8} } func (m *AccessRequests) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1240,7 +1311,7 @@ func (m *PluginDataSeq) Reset() { *m = PluginDataSeq{} } func (m *PluginDataSeq) String() string { return proto.CompactTextString(m) } func (*PluginDataSeq) ProtoMessage() {} func (*PluginDataSeq) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{9} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{9} } func (m *PluginDataSeq) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1306,7 +1377,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_authservice_a2d5604285d9f75d, []int{10} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{10} } func (m *RequestStateSetter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1382,7 +1453,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_authservice_a2d5604285d9f75d, []int{11} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{11} } func (m *RequestID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1432,7 +1503,7 @@ func (m *RotateResetPasswordTokenSecretsRequest) Reset() { func (m *RotateResetPasswordTokenSecretsRequest) String() string { return proto.CompactTextString(m) } func (*RotateResetPasswordTokenSecretsRequest) ProtoMessage() {} func (*RotateResetPasswordTokenSecretsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{12} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{12} } func (m *RotateResetPasswordTokenSecretsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1480,7 +1551,7 @@ func (m *GetResetPasswordTokenRequest) Reset() { *m = GetResetPasswordTo func (m *GetResetPasswordTokenRequest) String() string { return proto.CompactTextString(m) } func (*GetResetPasswordTokenRequest) ProtoMessage() {} func (*GetResetPasswordTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{13} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{13} } func (m *GetResetPasswordTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1534,7 +1605,7 @@ func (m *CreateResetPasswordTokenRequest) Reset() { *m = CreateResetPass func (m *CreateResetPasswordTokenRequest) String() string { return proto.CompactTextString(m) } func (*CreateResetPasswordTokenRequest) ProtoMessage() {} func (*CreateResetPasswordTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{14} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{14} } func (m *CreateResetPasswordTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1595,7 +1666,7 @@ func (m *PingRequest) Reset() { *m = PingRequest{} } func (m *PingRequest) String() string { return proto.CompactTextString(m) } func (*PingRequest) ProtoMessage() {} func (*PingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{15} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{15} } func (m *PingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1639,7 +1710,7 @@ func (m *PingResponse) Reset() { *m = PingResponse{} } func (m *PingResponse) String() string { return proto.CompactTextString(m) } func (*PingResponse) ProtoMessage() {} func (*PingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{16} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{16} } func (m *PingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1695,7 +1766,7 @@ func (m *DeleteUserRequest) Reset() { *m = DeleteUserRequest{} } func (m *DeleteUserRequest) String() string { return proto.CompactTextString(m) } func (*DeleteUserRequest) ProtoMessage() {} func (*DeleteUserRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{17} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{17} } func (m *DeleteUserRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1743,7 +1814,7 @@ func (m *Semaphores) Reset() { *m = Semaphores{} } func (m *Semaphores) String() string { return proto.CompactTextString(m) } func (*Semaphores) ProtoMessage() {} func (*Semaphores) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{18} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{18} } func (m *Semaphores) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1800,7 +1871,7 @@ func (m *AuditStreamRequest) Reset() { *m = AuditStreamRequest{} } func (m *AuditStreamRequest) String() string { return proto.CompactTextString(m) } func (*AuditStreamRequest) ProtoMessage() {} func (*AuditStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{19} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{19} } func (m *AuditStreamRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2116,7 @@ func (m *AuditStreamStatus) Reset() { *m = AuditStreamStatus{} } func (m *AuditStreamStatus) String() string { return proto.CompactTextString(m) } func (*AuditStreamStatus) ProtoMessage() {} func (*AuditStreamStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{20} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{20} } func (m *AuditStreamStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2093,7 +2164,7 @@ func (m *CreateStream) Reset() { *m = CreateStream{} } func (m *CreateStream) String() string { return proto.CompactTextString(m) } func (*CreateStream) ProtoMessage() {} func (*CreateStream) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{21} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{21} } func (m *CreateStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2144,7 +2215,7 @@ func (m *ResumeStream) Reset() { *m = ResumeStream{} } func (m *ResumeStream) String() string { return proto.CompactTextString(m) } func (*ResumeStream) ProtoMessage() {} func (*ResumeStream) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{22} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{22} } func (m *ResumeStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2199,7 +2270,7 @@ func (m *CompleteStream) Reset() { *m = CompleteStream{} } func (m *CompleteStream) String() string { return proto.CompactTextString(m) } func (*CompleteStream) ProtoMessage() {} func (*CompleteStream) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{23} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{23} } func (m *CompleteStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2239,7 +2310,7 @@ func (m *FlushAndCloseStream) Reset() { *m = FlushAndCloseStream{} } func (m *FlushAndCloseStream) String() string { return proto.CompactTextString(m) } func (*FlushAndCloseStream) ProtoMessage() {} func (*FlushAndCloseStream) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{24} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{24} } func (m *FlushAndCloseStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2283,7 +2354,7 @@ func (m *GetAppServersRequest) Reset() { *m = GetAppServersRequest{} } func (m *GetAppServersRequest) String() string { return proto.CompactTextString(m) } func (*GetAppServersRequest) ProtoMessage() {} func (*GetAppServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{25} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{25} } func (m *GetAppServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2339,7 +2410,7 @@ func (m *GetAppServersResponse) Reset() { *m = GetAppServersResponse{} } func (m *GetAppServersResponse) String() string { return proto.CompactTextString(m) } func (*GetAppServersResponse) ProtoMessage() {} func (*GetAppServersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{26} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{26} } func (m *GetAppServersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2387,7 +2458,7 @@ func (m *UpsertAppServerRequest) Reset() { *m = UpsertAppServerRequest{} func (m *UpsertAppServerRequest) String() string { return proto.CompactTextString(m) } func (*UpsertAppServerRequest) ProtoMessage() {} func (*UpsertAppServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{27} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{27} } func (m *UpsertAppServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2438,7 +2509,7 @@ func (m *DeleteAppServerRequest) Reset() { *m = DeleteAppServerRequest{} func (m *DeleteAppServerRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAppServerRequest) ProtoMessage() {} func (*DeleteAppServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{28} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{28} } func (m *DeleteAppServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2494,7 +2565,7 @@ func (m *DeleteAllAppServersRequest) Reset() { *m = DeleteAllAppServersR func (m *DeleteAllAppServersRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllAppServersRequest) ProtoMessage() {} func (*DeleteAllAppServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{29} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{29} } func (m *DeleteAllAppServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2550,7 +2621,7 @@ func (m *GenerateAppTokenRequest) Reset() { *m = GenerateAppTokenRequest func (m *GenerateAppTokenRequest) String() string { return proto.CompactTextString(m) } func (*GenerateAppTokenRequest) ProtoMessage() {} func (*GenerateAppTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{30} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{30} } func (m *GenerateAppTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2619,7 +2690,7 @@ func (m *GenerateAppTokenResponse) Reset() { *m = GenerateAppTokenRespon func (m *GenerateAppTokenResponse) String() string { return proto.CompactTextString(m) } func (*GenerateAppTokenResponse) ProtoMessage() {} func (*GenerateAppTokenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{31} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{31} } func (m *GenerateAppTokenResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2668,7 +2739,7 @@ func (m *GetAppSessionRequest) Reset() { *m = GetAppSessionRequest{} } func (m *GetAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*GetAppSessionRequest) ProtoMessage() {} func (*GetAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{32} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{32} } func (m *GetAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2717,7 +2788,7 @@ func (m *GetAppSessionResponse) Reset() { *m = GetAppSessionResponse{} } func (m *GetAppSessionResponse) String() string { return proto.CompactTextString(m) } func (*GetAppSessionResponse) ProtoMessage() {} func (*GetAppSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{33} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{33} } func (m *GetAppSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2766,7 +2837,7 @@ func (m *GetAppSessionsResponse) Reset() { *m = GetAppSessionsResponse{} func (m *GetAppSessionsResponse) String() string { return proto.CompactTextString(m) } func (*GetAppSessionsResponse) ProtoMessage() {} func (*GetAppSessionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{34} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{34} } func (m *GetAppSessionsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2821,7 +2892,7 @@ func (m *CreateAppSessionRequest) Reset() { *m = CreateAppSessionRequest func (m *CreateAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*CreateAppSessionRequest) ProtoMessage() {} func (*CreateAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{35} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{35} } func (m *CreateAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2891,7 +2962,7 @@ func (m *CreateAppSessionResponse) Reset() { *m = CreateAppSessionRespon func (m *CreateAppSessionResponse) String() string { return proto.CompactTextString(m) } func (*CreateAppSessionResponse) ProtoMessage() {} func (*CreateAppSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{36} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{36} } func (m *CreateAppSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2939,7 +3010,7 @@ func (m *DeleteAppSessionRequest) Reset() { *m = DeleteAppSessionRequest func (m *DeleteAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAppSessionRequest) ProtoMessage() {} func (*DeleteAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{37} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{37} } func (m *DeleteAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2975,6 +3046,202 @@ func (m *DeleteAppSessionRequest) GetSessionID() string { return "" } +// GetWebSessionResponse contains the requested web session. +type GetWebSessionResponse struct { + // Session is the web session. + Session *types.WebSessionV2 `protobuf:"bytes,1,opt,name=Session" json:"session"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebSessionResponse) Reset() { *m = GetWebSessionResponse{} } +func (m *GetWebSessionResponse) String() string { return proto.CompactTextString(m) } +func (*GetWebSessionResponse) ProtoMessage() {} +func (*GetWebSessionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_authservice_65caaa95923b9fbe, []int{38} +} +func (m *GetWebSessionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebSessionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebSessionResponse.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 *GetWebSessionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebSessionResponse.Merge(dst, src) +} +func (m *GetWebSessionResponse) XXX_Size() int { + return m.Size() +} +func (m *GetWebSessionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebSessionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebSessionResponse proto.InternalMessageInfo + +func (m *GetWebSessionResponse) GetSession() *types.WebSessionV2 { + if m != nil { + return m.Session + } + return nil +} + +// GetWebSessionsResponse contains all the requested web sessions. +type GetWebSessionsResponse struct { + // Sessions is a list of web sessions. + Sessions []*types.WebSessionV2 `protobuf:"bytes,1,rep,name=Sessions" json:"sessions"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebSessionsResponse) Reset() { *m = GetWebSessionsResponse{} } +func (m *GetWebSessionsResponse) String() string { return proto.CompactTextString(m) } +func (*GetWebSessionsResponse) ProtoMessage() {} +func (*GetWebSessionsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_authservice_65caaa95923b9fbe, []int{39} +} +func (m *GetWebSessionsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebSessionsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebSessionsResponse.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 *GetWebSessionsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebSessionsResponse.Merge(dst, src) +} +func (m *GetWebSessionsResponse) XXX_Size() int { + return m.Size() +} +func (m *GetWebSessionsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebSessionsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebSessionsResponse proto.InternalMessageInfo + +func (m *GetWebSessionsResponse) GetSessions() []*types.WebSessionV2 { + if m != nil { + return m.Sessions + } + return nil +} + +// GetWebTokenResponse contains the requested web token. +type GetWebTokenResponse struct { + // Token is the web token being requested. + Token *types.WebTokenV3 `protobuf:"bytes,1,opt,name=Token" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebTokenResponse) Reset() { *m = GetWebTokenResponse{} } +func (m *GetWebTokenResponse) String() string { return proto.CompactTextString(m) } +func (*GetWebTokenResponse) ProtoMessage() {} +func (*GetWebTokenResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_authservice_65caaa95923b9fbe, []int{40} +} +func (m *GetWebTokenResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebTokenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebTokenResponse.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 *GetWebTokenResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebTokenResponse.Merge(dst, src) +} +func (m *GetWebTokenResponse) XXX_Size() int { + return m.Size() +} +func (m *GetWebTokenResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebTokenResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebTokenResponse proto.InternalMessageInfo + +func (m *GetWebTokenResponse) GetToken() *types.WebTokenV3 { + if m != nil { + return m.Token + } + return nil +} + +// GetWebTokensResponse contains all the requested web tokens. +type GetWebTokensResponse struct { + // Tokens is a list of web tokens. + Tokens []*types.WebTokenV3 `protobuf:"bytes,1,rep,name=Tokens" json:"tokens"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebTokensResponse) Reset() { *m = GetWebTokensResponse{} } +func (m *GetWebTokensResponse) String() string { return proto.CompactTextString(m) } +func (*GetWebTokensResponse) ProtoMessage() {} +func (*GetWebTokensResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_authservice_65caaa95923b9fbe, []int{41} +} +func (m *GetWebTokensResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebTokensResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebTokensResponse.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 *GetWebTokensResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebTokensResponse.Merge(dst, src) +} +func (m *GetWebTokensResponse) XXX_Size() int { + return m.Size() +} +func (m *GetWebTokensResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebTokensResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebTokensResponse proto.InternalMessageInfo + +func (m *GetWebTokensResponse) GetTokens() []*types.WebTokenV3 { + if m != nil { + return m.Tokens + } + return nil +} + // GetKubeServicesRequest are the parameters used to request kubernetes services. type GetKubeServicesRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -2986,7 +3253,7 @@ func (m *GetKubeServicesRequest) Reset() { *m = GetKubeServicesRequest{} func (m *GetKubeServicesRequest) String() string { return proto.CompactTextString(m) } func (*GetKubeServicesRequest) ProtoMessage() {} func (*GetKubeServicesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{38} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{42} } func (m *GetKubeServicesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3029,7 +3296,7 @@ func (m *GetKubeServicesResponse) Reset() { *m = GetKubeServicesResponse func (m *GetKubeServicesResponse) String() string { return proto.CompactTextString(m) } func (*GetKubeServicesResponse) ProtoMessage() {} func (*GetKubeServicesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{39} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{43} } func (m *GetKubeServicesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3078,7 +3345,7 @@ func (m *UpsertKubeServiceRequest) Reset() { *m = UpsertKubeServiceReque func (m *UpsertKubeServiceRequest) String() string { return proto.CompactTextString(m) } func (*UpsertKubeServiceRequest) ProtoMessage() {} func (*UpsertKubeServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{40} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{44} } func (m *UpsertKubeServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3127,7 +3394,7 @@ func (m *DeleteKubeServiceRequest) Reset() { *m = DeleteKubeServiceReque func (m *DeleteKubeServiceRequest) String() string { return proto.CompactTextString(m) } func (*DeleteKubeServiceRequest) ProtoMessage() {} func (*DeleteKubeServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{41} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{45} } func (m *DeleteKubeServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3174,7 +3441,7 @@ func (m *DeleteAllKubeServicesRequest) Reset() { *m = DeleteAllKubeServi func (m *DeleteAllKubeServicesRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllKubeServicesRequest) ProtoMessage() {} func (*DeleteAllKubeServicesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{42} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{46} } func (m *DeleteAllKubeServicesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3218,7 +3485,7 @@ func (m *GetDatabaseServersRequest) Reset() { *m = GetDatabaseServersReq func (m *GetDatabaseServersRequest) String() string { return proto.CompactTextString(m) } func (*GetDatabaseServersRequest) ProtoMessage() {} func (*GetDatabaseServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{43} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{47} } func (m *GetDatabaseServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3274,7 +3541,7 @@ func (m *GetDatabaseServersResponse) Reset() { *m = GetDatabaseServersRe func (m *GetDatabaseServersResponse) String() string { return proto.CompactTextString(m) } func (*GetDatabaseServersResponse) ProtoMessage() {} func (*GetDatabaseServersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{44} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{48} } func (m *GetDatabaseServersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3323,7 +3590,7 @@ func (m *UpsertDatabaseServerRequest) Reset() { *m = UpsertDatabaseServe func (m *UpsertDatabaseServerRequest) String() string { return proto.CompactTextString(m) } func (*UpsertDatabaseServerRequest) ProtoMessage() {} func (*UpsertDatabaseServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{45} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{49} } func (m *UpsertDatabaseServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3376,7 +3643,7 @@ func (m *DeleteDatabaseServerRequest) Reset() { *m = DeleteDatabaseServe func (m *DeleteDatabaseServerRequest) String() string { return proto.CompactTextString(m) } func (*DeleteDatabaseServerRequest) ProtoMessage() {} func (*DeleteDatabaseServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{46} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{50} } func (m *DeleteDatabaseServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3439,7 +3706,7 @@ func (m *DeleteAllDatabaseServersRequest) Reset() { *m = DeleteAllDataba func (m *DeleteAllDatabaseServersRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllDatabaseServersRequest) ProtoMessage() {} func (*DeleteAllDatabaseServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{47} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{51} } func (m *DeleteAllDatabaseServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3491,7 +3758,7 @@ func (m *DatabaseCSRRequest) Reset() { *m = DatabaseCSRRequest{} } func (m *DatabaseCSRRequest) String() string { return proto.CompactTextString(m) } func (*DatabaseCSRRequest) ProtoMessage() {} func (*DatabaseCSRRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{48} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{52} } func (m *DatabaseCSRRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3549,7 +3816,7 @@ func (m *DatabaseCSRResponse) Reset() { *m = DatabaseCSRResponse{} } func (m *DatabaseCSRResponse) String() string { return proto.CompactTextString(m) } func (*DatabaseCSRResponse) ProtoMessage() {} func (*DatabaseCSRResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{49} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{53} } func (m *DatabaseCSRResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3610,7 +3877,7 @@ func (m *DatabaseCertRequest) Reset() { *m = DatabaseCertRequest{} } func (m *DatabaseCertRequest) String() string { return proto.CompactTextString(m) } func (*DatabaseCertRequest) ProtoMessage() {} func (*DatabaseCertRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{50} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{54} } func (m *DatabaseCertRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3675,7 +3942,7 @@ func (m *DatabaseCertResponse) Reset() { *m = DatabaseCertResponse{} } func (m *DatabaseCertResponse) String() string { return proto.CompactTextString(m) } func (*DatabaseCertResponse) ProtoMessage() {} func (*DatabaseCertResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{51} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{55} } func (m *DatabaseCertResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3737,7 +4004,7 @@ func (m *MFAAuthenticateChallenge) Reset() { *m = MFAAuthenticateChallen func (m *MFAAuthenticateChallenge) String() string { return proto.CompactTextString(m) } func (*MFAAuthenticateChallenge) ProtoMessage() {} func (*MFAAuthenticateChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{52} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{56} } func (m *MFAAuthenticateChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3796,7 +4063,7 @@ func (m *MFAAuthenticateResponse) Reset() { *m = MFAAuthenticateResponse func (m *MFAAuthenticateResponse) String() string { return proto.CompactTextString(m) } func (*MFAAuthenticateResponse) ProtoMessage() {} func (*MFAAuthenticateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{53} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{57} } func (m *MFAAuthenticateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3950,7 +4217,7 @@ func (m *U2FChallenge) Reset() { *m = U2FChallenge{} } func (m *U2FChallenge) String() string { return proto.CompactTextString(m) } func (*U2FChallenge) ProtoMessage() {} func (*U2FChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{54} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{58} } func (m *U2FChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4014,7 +4281,7 @@ func (m *U2FResponse) Reset() { *m = U2FResponse{} } func (m *U2FResponse) String() string { return proto.CompactTextString(m) } func (*U2FResponse) ProtoMessage() {} func (*U2FResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{55} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{59} } func (m *U2FResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4075,7 +4342,7 @@ func (m *TOTPChallenge) Reset() { *m = TOTPChallenge{} } func (m *TOTPChallenge) String() string { return proto.CompactTextString(m) } func (*TOTPChallenge) ProtoMessage() {} func (*TOTPChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{56} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{60} } func (m *TOTPChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4116,7 +4383,7 @@ func (m *TOTPResponse) Reset() { *m = TOTPResponse{} } func (m *TOTPResponse) String() string { return proto.CompactTextString(m) } func (*TOTPResponse) ProtoMessage() {} func (*TOTPResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{57} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{61} } func (m *TOTPResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4169,7 +4436,7 @@ func (m *MFARegisterChallenge) Reset() { *m = MFARegisterChallenge{} } func (m *MFARegisterChallenge) String() string { return proto.CompactTextString(m) } func (*MFARegisterChallenge) ProtoMessage() {} func (*MFARegisterChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{58} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{62} } func (m *MFARegisterChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4324,7 +4591,7 @@ func (m *MFARegisterResponse) Reset() { *m = MFARegisterResponse{} } func (m *MFARegisterResponse) String() string { return proto.CompactTextString(m) } func (*MFARegisterResponse) ProtoMessage() {} func (*MFARegisterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{59} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{63} } func (m *MFARegisterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4477,7 +4744,7 @@ func (m *U2FRegisterChallenge) Reset() { *m = U2FRegisterChallenge{} } func (m *U2FRegisterChallenge) String() string { return proto.CompactTextString(m) } func (*U2FRegisterChallenge) ProtoMessage() {} func (*U2FRegisterChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{60} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{64} } func (m *U2FRegisterChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4533,7 +4800,7 @@ func (m *U2FRegisterResponse) Reset() { *m = U2FRegisterResponse{} } func (m *U2FRegisterResponse) String() string { return proto.CompactTextString(m) } func (*U2FRegisterResponse) ProtoMessage() {} func (*U2FRegisterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{61} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{65} } func (m *U2FRegisterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4599,7 +4866,7 @@ func (m *TOTPRegisterChallenge) Reset() { *m = TOTPRegisterChallenge{} } func (m *TOTPRegisterChallenge) String() string { return proto.CompactTextString(m) } func (*TOTPRegisterChallenge) ProtoMessage() {} func (*TOTPRegisterChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{62} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{66} } func (m *TOTPRegisterChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4682,7 +4949,7 @@ func (m *TOTPRegisterResponse) Reset() { *m = TOTPRegisterResponse{} } func (m *TOTPRegisterResponse) String() string { return proto.CompactTextString(m) } func (*TOTPRegisterResponse) ProtoMessage() {} func (*TOTPRegisterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{63} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{67} } func (m *TOTPRegisterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4734,7 +5001,7 @@ func (m *AddMFADeviceRequest) Reset() { *m = AddMFADeviceRequest{} } func (m *AddMFADeviceRequest) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceRequest) ProtoMessage() {} func (*AddMFADeviceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{64} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{68} } func (m *AddMFADeviceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4921,7 +5188,7 @@ func (m *AddMFADeviceResponse) Reset() { *m = AddMFADeviceResponse{} } func (m *AddMFADeviceResponse) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceResponse) ProtoMessage() {} func (*AddMFADeviceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{65} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{69} } func (m *AddMFADeviceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5104,7 +5371,7 @@ func (m *AddMFADeviceRequestInit) Reset() { *m = AddMFADeviceRequestInit func (m *AddMFADeviceRequestInit) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceRequestInit) ProtoMessage() {} func (*AddMFADeviceRequestInit) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{66} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{70} } func (m *AddMFADeviceRequestInit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5159,7 +5426,7 @@ func (m *AddMFADeviceResponseAck) Reset() { *m = AddMFADeviceResponseAck func (m *AddMFADeviceResponseAck) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceResponseAck) ProtoMessage() {} func (*AddMFADeviceResponseAck) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{67} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{71} } func (m *AddMFADeviceResponseAck) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5211,7 +5478,7 @@ func (m *DeleteMFADeviceRequest) Reset() { *m = DeleteMFADeviceRequest{} func (m *DeleteMFADeviceRequest) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceRequest) ProtoMessage() {} func (*DeleteMFADeviceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{68} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{72} } func (m *DeleteMFADeviceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5365,7 +5632,7 @@ func (m *DeleteMFADeviceResponse) Reset() { *m = DeleteMFADeviceResponse func (m *DeleteMFADeviceResponse) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceResponse) ProtoMessage() {} func (*DeleteMFADeviceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{69} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{73} } func (m *DeleteMFADeviceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5518,7 +5785,7 @@ func (m *DeleteMFADeviceRequestInit) Reset() { *m = DeleteMFADeviceReque func (m *DeleteMFADeviceRequestInit) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceRequestInit) ProtoMessage() {} func (*DeleteMFADeviceRequestInit) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{70} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{74} } func (m *DeleteMFADeviceRequestInit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5565,7 +5832,7 @@ func (m *DeleteMFADeviceResponseAck) Reset() { *m = DeleteMFADeviceRespo func (m *DeleteMFADeviceResponseAck) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceResponseAck) ProtoMessage() {} func (*DeleteMFADeviceResponseAck) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{71} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{75} } func (m *DeleteMFADeviceResponseAck) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5605,7 +5872,7 @@ func (m *GetMFADevicesRequest) Reset() { *m = GetMFADevicesRequest{} } func (m *GetMFADevicesRequest) String() string { return proto.CompactTextString(m) } func (*GetMFADevicesRequest) ProtoMessage() {} func (*GetMFADevicesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{72} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{76} } func (m *GetMFADevicesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5646,7 +5913,7 @@ func (m *GetMFADevicesResponse) Reset() { *m = GetMFADevicesResponse{} } func (m *GetMFADevicesResponse) String() string { return proto.CompactTextString(m) } func (*GetMFADevicesResponse) ProtoMessage() {} func (*GetMFADevicesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_authservice_a2d5604285d9f75d, []int{73} + return fileDescriptor_authservice_65caaa95923b9fbe, []int{77} } func (m *GetMFADevicesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5722,6 +5989,10 @@ func init() { proto.RegisterType((*CreateAppSessionRequest)(nil), "proto.CreateAppSessionRequest") proto.RegisterType((*CreateAppSessionResponse)(nil), "proto.CreateAppSessionResponse") proto.RegisterType((*DeleteAppSessionRequest)(nil), "proto.DeleteAppSessionRequest") + proto.RegisterType((*GetWebSessionResponse)(nil), "proto.GetWebSessionResponse") + proto.RegisterType((*GetWebSessionsResponse)(nil), "proto.GetWebSessionsResponse") + proto.RegisterType((*GetWebTokenResponse)(nil), "proto.GetWebTokenResponse") + proto.RegisterType((*GetWebTokensResponse)(nil), "proto.GetWebTokensResponse") proto.RegisterType((*GetKubeServicesRequest)(nil), "proto.GetKubeServicesRequest") proto.RegisterType((*GetKubeServicesResponse)(nil), "proto.GetKubeServicesResponse") proto.RegisterType((*UpsertKubeServiceRequest)(nil), "proto.UpsertKubeServiceRequest") @@ -5851,6 +6122,22 @@ type AuthServiceClient interface { DeleteAppSession(ctx context.Context, in *DeleteAppSessionRequest, opts ...grpc.CallOption) (*empty.Empty, error) // DeleteAllAppSessions removes all application web sessions. DeleteAllAppSessions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) + // GetWebSession gets a web session. + GetWebSession(ctx context.Context, in *types.GetWebSessionRequest, opts ...grpc.CallOption) (*GetWebSessionResponse, error) + // GetWebSessions gets all web sessions. + GetWebSessions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetWebSessionsResponse, error) + // DeleteWebSession deletes a web session. + DeleteWebSession(ctx context.Context, in *types.DeleteWebSessionRequest, opts ...grpc.CallOption) (*empty.Empty, error) + // DeleteAllWebSessions deletes all web sessions. + DeleteAllWebSessions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) + // GetWebToken gets a web token. + GetWebToken(ctx context.Context, in *types.GetWebTokenRequest, opts ...grpc.CallOption) (*GetWebTokenResponse, error) + // GetWebTokens gets all web tokens. + GetWebTokens(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetWebTokensResponse, error) + // DeleteWebToken deletes a web token. + DeleteWebToken(ctx context.Context, in *types.DeleteWebTokenRequest, opts ...grpc.CallOption) (*empty.Empty, error) + // DeleteAllWebTokens deletes all web tokens. + DeleteAllWebTokens(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) // UpdateRemoteCluster updates remote cluster UpdateRemoteCluster(ctx context.Context, in *types.RemoteClusterV3, opts ...grpc.CallOption) (*empty.Empty, error) // GetKubeServices gets all kubernetes services. @@ -6334,6 +6621,78 @@ func (c *authServiceClient) DeleteAllAppSessions(ctx context.Context, in *empty. return out, nil } +func (c *authServiceClient) GetWebSession(ctx context.Context, in *types.GetWebSessionRequest, opts ...grpc.CallOption) (*GetWebSessionResponse, error) { + out := new(GetWebSessionResponse) + err := c.cc.Invoke(ctx, "/proto.AuthService/GetWebSession", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetWebSessions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetWebSessionsResponse, error) { + out := new(GetWebSessionsResponse) + err := c.cc.Invoke(ctx, "/proto.AuthService/GetWebSessions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteWebSession(ctx context.Context, in *types.DeleteWebSessionRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/proto.AuthService/DeleteWebSession", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteAllWebSessions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/proto.AuthService/DeleteAllWebSessions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetWebToken(ctx context.Context, in *types.GetWebTokenRequest, opts ...grpc.CallOption) (*GetWebTokenResponse, error) { + out := new(GetWebTokenResponse) + err := c.cc.Invoke(ctx, "/proto.AuthService/GetWebToken", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetWebTokens(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetWebTokensResponse, error) { + out := new(GetWebTokensResponse) + err := c.cc.Invoke(ctx, "/proto.AuthService/GetWebTokens", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteWebToken(ctx context.Context, in *types.DeleteWebTokenRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/proto.AuthService/DeleteWebToken", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteAllWebTokens(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/proto.AuthService/DeleteAllWebTokens", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *authServiceClient) UpdateRemoteCluster(ctx context.Context, in *types.RemoteClusterV3, opts ...grpc.CallOption) (*empty.Empty, error) { out := new(empty.Empty) err := c.cc.Invoke(ctx, "/proto.AuthService/UpdateRemoteCluster", in, out, opts...) @@ -6585,6 +6944,22 @@ type AuthServiceServer interface { DeleteAppSession(context.Context, *DeleteAppSessionRequest) (*empty.Empty, error) // DeleteAllAppSessions removes all application web sessions. DeleteAllAppSessions(context.Context, *empty.Empty) (*empty.Empty, error) + // GetWebSession gets a web session. + GetWebSession(context.Context, *types.GetWebSessionRequest) (*GetWebSessionResponse, error) + // GetWebSessions gets all web sessions. + GetWebSessions(context.Context, *empty.Empty) (*GetWebSessionsResponse, error) + // DeleteWebSession deletes a web session. + DeleteWebSession(context.Context, *types.DeleteWebSessionRequest) (*empty.Empty, error) + // DeleteAllWebSessions deletes all web sessions. + DeleteAllWebSessions(context.Context, *empty.Empty) (*empty.Empty, error) + // GetWebToken gets a web token. + GetWebToken(context.Context, *types.GetWebTokenRequest) (*GetWebTokenResponse, error) + // GetWebTokens gets all web tokens. + GetWebTokens(context.Context, *empty.Empty) (*GetWebTokensResponse, error) + // DeleteWebToken deletes a web token. + DeleteWebToken(context.Context, *types.DeleteWebTokenRequest) (*empty.Empty, error) + // DeleteAllWebTokens deletes all web tokens. + DeleteAllWebTokens(context.Context, *empty.Empty) (*empty.Empty, error) // UpdateRemoteCluster updates remote cluster UpdateRemoteCluster(context.Context, *types.RemoteClusterV3) (*empty.Empty, error) // GetKubeServices gets all kubernetes services. @@ -7326,6 +7701,150 @@ func _AuthService_DeleteAllAppSessions_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _AuthService_GetWebSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(types.GetWebSessionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetWebSession(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/GetWebSession", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetWebSession(ctx, req.(*types.GetWebSessionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetWebSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetWebSessions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/GetWebSessions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetWebSessions(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteWebSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(types.DeleteWebSessionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteWebSession(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/DeleteWebSession", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteWebSession(ctx, req.(*types.DeleteWebSessionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteAllWebSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteAllWebSessions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/DeleteAllWebSessions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteAllWebSessions(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetWebToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(types.GetWebTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetWebToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/GetWebToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetWebToken(ctx, req.(*types.GetWebTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetWebTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetWebTokens(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/GetWebTokens", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetWebTokens(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteWebToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(types.DeleteWebTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteWebToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/DeleteWebToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteWebToken(ctx, req.(*types.DeleteWebTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteAllWebTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteAllWebTokens(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/DeleteAllWebTokens", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteAllWebTokens(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _AuthService_UpdateRemoteCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(types.RemoteClusterV3) if err := dec(in); err != nil { @@ -7730,6 +8249,38 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ MethodName: "DeleteAllAppSessions", Handler: _AuthService_DeleteAllAppSessions_Handler, }, + { + MethodName: "GetWebSession", + Handler: _AuthService_GetWebSession_Handler, + }, + { + MethodName: "GetWebSessions", + Handler: _AuthService_GetWebSessions_Handler, + }, + { + MethodName: "DeleteWebSession", + Handler: _AuthService_DeleteWebSession_Handler, + }, + { + MethodName: "DeleteAllWebSessions", + Handler: _AuthService_DeleteAllWebSessions_Handler, + }, + { + MethodName: "GetWebToken", + Handler: _AuthService_GetWebToken_Handler, + }, + { + MethodName: "GetWebTokens", + Handler: _AuthService_GetWebTokens_Handler, + }, + { + MethodName: "DeleteWebToken", + Handler: _AuthService_DeleteWebToken_Handler, + }, + { + MethodName: "DeleteAllWebTokens", + Handler: _AuthService_DeleteAllWebTokens_Handler, + }, { MethodName: "UpdateRemoteCluster", Handler: _AuthService_UpdateRemoteCluster_Handler, @@ -8078,6 +8629,38 @@ func (m *Event_DatabaseServer) MarshalTo(dAtA []byte) (int, error) { } return i, nil } +func (m *Event_WebSession) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.WebSession != nil { + dAtA[i] = 0x92 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(m.WebSession.Size())) + n18, err := m.WebSession.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n18 + } + return i, nil +} +func (m *Event_WebToken) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.WebToken != nil { + dAtA[i] = 0x9a + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(m.WebToken.Size())) + n19, err := m.WebToken.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n19 + } + return i, nil +} func (m *Watch) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8165,6 +8748,12 @@ func (m *WatchKind) MarshalTo(dAtA []byte) (int, error) { i += copy(dAtA[i:], v) } } + if len(m.SubKind) > 0 { + dAtA[i] = 0x2a + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.SubKind))) + i += copy(dAtA[i:], m.SubKind) + } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -8234,11 +8823,11 @@ func (m *UserCertsRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintAuthservice(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires))) - n18, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) + n20, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) if err != nil { return 0, err } - i += n18 + i += n20 if len(m.Format) > 0 { dAtA[i] = 0x22 i++ @@ -8275,11 +8864,11 @@ func (m *UserCertsRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x42 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.RouteToDatabase.Size())) - n19, err := m.RouteToDatabase.MarshalTo(dAtA[i:]) + n21, err := m.RouteToDatabase.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n19 + i += n21 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -8506,11 +9095,11 @@ func (m *RequestStateSetter) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x2a i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Annotations.Size())) - n20, err := m.Annotations.MarshalTo(dAtA[i:]) + n22, err := m.Annotations.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n20 + i += n22 if len(m.Roles) > 0 { for _, s := range m.Roles { dAtA[i] = 0x32 @@ -8781,11 +9370,11 @@ func (m *AuditStreamRequest) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Request != nil { - nn21, err := m.Request.MarshalTo(dAtA[i:]) + nn23, err := m.Request.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn21 + i += nn23 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -8799,11 +9388,11 @@ func (m *AuditStreamRequest_CreateStream) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.CreateStream.Size())) - n22, err := m.CreateStream.MarshalTo(dAtA[i:]) + n24, err := m.CreateStream.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n22 + i += n24 } return i, nil } @@ -8813,11 +9402,11 @@ func (m *AuditStreamRequest_ResumeStream) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.ResumeStream.Size())) - n23, err := m.ResumeStream.MarshalTo(dAtA[i:]) + n25, err := m.ResumeStream.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n23 + i += n25 } return i, nil } @@ -8827,11 +9416,11 @@ func (m *AuditStreamRequest_CompleteStream) MarshalTo(dAtA []byte) (int, error) dAtA[i] = 0x1a i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.CompleteStream.Size())) - n24, err := m.CompleteStream.MarshalTo(dAtA[i:]) + n26, err := m.CompleteStream.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n24 + i += n26 } return i, nil } @@ -8841,11 +9430,11 @@ func (m *AuditStreamRequest_FlushAndCloseStream) MarshalTo(dAtA []byte) (int, er dAtA[i] = 0x22 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.FlushAndCloseStream.Size())) - n25, err := m.FlushAndCloseStream.MarshalTo(dAtA[i:]) + n27, err := m.FlushAndCloseStream.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n25 + i += n27 } return i, nil } @@ -8855,11 +9444,11 @@ func (m *AuditStreamRequest_Event) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x2a i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Event.Size())) - n26, err := m.Event.MarshalTo(dAtA[i:]) + n28, err := m.Event.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n26 + i += n28 } return i, nil } @@ -9081,11 +9670,11 @@ func (m *UpsertAppServerRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Server.Size())) - n27, err := m.Server.MarshalTo(dAtA[i:]) + n29, err := m.Server.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n27 + i += n29 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9198,11 +9787,11 @@ func (m *GenerateAppTokenRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintAuthservice(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires))) - n28, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) + n30, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i:]) if err != nil { return 0, err } - i += n28 + i += n30 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -9282,11 +9871,11 @@ func (m *GetAppSessionResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Session.Size())) - n29, err := m.Session.MarshalTo(dAtA[i:]) + n31, err := m.Session.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n29 + i += n31 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9391,11 +9980,11 @@ func (m *CreateAppSessionResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Session.Size())) - n30, err := m.Session.MarshalTo(dAtA[i:]) + n32, err := m.Session.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n30 + i += n32 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9430,6 +10019,134 @@ func (m *DeleteAppSessionRequest) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *GetWebSessionResponse) 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 *GetWebSessionResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Session != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(m.Session.Size())) + n33, err := m.Session.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n33 + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *GetWebSessionsResponse) 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 *GetWebSessionsResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Sessions) > 0 { + for _, msg := range m.Sessions { + dAtA[i] = 0xa + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *GetWebTokenResponse) 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 *GetWebTokenResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Token != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(m.Token.Size())) + n34, err := m.Token.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 *GetWebTokensResponse) 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 *GetWebTokensResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Tokens) > 0 { + for _, msg := range m.Tokens { + dAtA[i] = 0xa + i++ + i = encodeVarintAuthservice(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func (m *GetKubeServicesRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -9503,11 +10220,11 @@ func (m *UpsertKubeServiceRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Server.Size())) - n31, err := m.Server.MarshalTo(dAtA[i:]) + n35, err := m.Server.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n31 + i += n35 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9652,11 +10369,11 @@ func (m *UpsertDatabaseServerRequest) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Server.Size())) - n32, err := m.Server.MarshalTo(dAtA[i:]) + n36, err := m.Server.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n32 + i += n36 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9902,11 +10619,11 @@ func (m *MFAAuthenticateChallenge) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.TOTP.Size())) - n33, err := m.TOTP.MarshalTo(dAtA[i:]) + n37, err := m.TOTP.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n33 + i += n37 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9930,11 +10647,11 @@ func (m *MFAAuthenticateResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Response != nil { - nn34, err := m.Response.MarshalTo(dAtA[i:]) + nn38, err := m.Response.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn34 + i += nn38 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -9948,11 +10665,11 @@ func (m *MFAAuthenticateResponse_U2F) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.U2F.Size())) - n35, err := m.U2F.MarshalTo(dAtA[i:]) + n39, err := m.U2F.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n35 + i += n39 } return i, nil } @@ -9962,11 +10679,11 @@ func (m *MFAAuthenticateResponse_TOTP) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.TOTP.Size())) - n36, err := m.TOTP.MarshalTo(dAtA[i:]) + n40, err := m.TOTP.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n36 + i += n40 } return i, nil } @@ -10112,11 +10829,11 @@ func (m *MFARegisterChallenge) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Request != nil { - nn37, err := m.Request.MarshalTo(dAtA[i:]) + nn41, err := m.Request.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn37 + i += nn41 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10130,11 +10847,11 @@ func (m *MFARegisterChallenge_U2F) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.U2F.Size())) - n38, err := m.U2F.MarshalTo(dAtA[i:]) + n42, err := m.U2F.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n38 + i += n42 } return i, nil } @@ -10144,11 +10861,11 @@ func (m *MFARegisterChallenge_TOTP) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.TOTP.Size())) - n39, err := m.TOTP.MarshalTo(dAtA[i:]) + n43, err := m.TOTP.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n39 + i += n43 } return i, nil } @@ -10168,11 +10885,11 @@ func (m *MFARegisterResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Response != nil { - nn40, err := m.Response.MarshalTo(dAtA[i:]) + nn44, err := m.Response.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn40 + i += nn44 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10186,11 +10903,11 @@ func (m *MFARegisterResponse_U2F) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.U2F.Size())) - n41, err := m.U2F.MarshalTo(dAtA[i:]) + n45, err := m.U2F.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n41 + i += n45 } return i, nil } @@ -10200,11 +10917,11 @@ func (m *MFARegisterResponse_TOTP) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.TOTP.Size())) - n42, err := m.TOTP.MarshalTo(dAtA[i:]) + n46, err := m.TOTP.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n42 + i += n46 } return i, nil } @@ -10372,11 +11089,11 @@ func (m *AddMFADeviceRequest) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Request != nil { - nn43, err := m.Request.MarshalTo(dAtA[i:]) + nn47, err := m.Request.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn43 + i += nn47 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10390,11 +11107,11 @@ func (m *AddMFADeviceRequest_Init) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Init.Size())) - n44, err := m.Init.MarshalTo(dAtA[i:]) + n48, err := m.Init.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n44 + i += n48 } return i, nil } @@ -10404,11 +11121,11 @@ func (m *AddMFADeviceRequest_ExistingMFAResponse) MarshalTo(dAtA []byte) (int, e dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.ExistingMFAResponse.Size())) - n45, err := m.ExistingMFAResponse.MarshalTo(dAtA[i:]) + n49, err := m.ExistingMFAResponse.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n45 + i += n49 } return i, nil } @@ -10418,11 +11135,11 @@ func (m *AddMFADeviceRequest_NewMFARegisterResponse) MarshalTo(dAtA []byte) (int dAtA[i] = 0x1a i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.NewMFARegisterResponse.Size())) - n46, err := m.NewMFARegisterResponse.MarshalTo(dAtA[i:]) + n50, err := m.NewMFARegisterResponse.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n46 + i += n50 } return i, nil } @@ -10442,11 +11159,11 @@ func (m *AddMFADeviceResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Response != nil { - nn47, err := m.Response.MarshalTo(dAtA[i:]) + nn51, err := m.Response.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn47 + i += nn51 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10460,11 +11177,11 @@ func (m *AddMFADeviceResponse_ExistingMFAChallenge) MarshalTo(dAtA []byte) (int, dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.ExistingMFAChallenge.Size())) - n48, err := m.ExistingMFAChallenge.MarshalTo(dAtA[i:]) + n52, err := m.ExistingMFAChallenge.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n48 + i += n52 } return i, nil } @@ -10474,11 +11191,11 @@ func (m *AddMFADeviceResponse_NewMFARegisterChallenge) MarshalTo(dAtA []byte) (i dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.NewMFARegisterChallenge.Size())) - n49, err := m.NewMFARegisterChallenge.MarshalTo(dAtA[i:]) + n53, err := m.NewMFARegisterChallenge.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n49 + i += n53 } return i, nil } @@ -10488,11 +11205,11 @@ func (m *AddMFADeviceResponse_Ack) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Ack.Size())) - n50, err := m.Ack.MarshalTo(dAtA[i:]) + n54, err := m.Ack.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n50 + i += n54 } return i, nil } @@ -10547,11 +11264,11 @@ func (m *AddMFADeviceResponseAck) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Device.Size())) - n51, err := m.Device.MarshalTo(dAtA[i:]) + n55, err := m.Device.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n51 + i += n55 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10575,11 +11292,11 @@ func (m *DeleteMFADeviceRequest) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Request != nil { - nn52, err := m.Request.MarshalTo(dAtA[i:]) + nn56, err := m.Request.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn52 + i += nn56 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10593,11 +11310,11 @@ func (m *DeleteMFADeviceRequest_Init) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Init.Size())) - n53, err := m.Init.MarshalTo(dAtA[i:]) + n57, err := m.Init.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n53 + i += n57 } return i, nil } @@ -10607,11 +11324,11 @@ func (m *DeleteMFADeviceRequest_MFAResponse) MarshalTo(dAtA []byte) (int, error) dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.MFAResponse.Size())) - n54, err := m.MFAResponse.MarshalTo(dAtA[i:]) + n58, err := m.MFAResponse.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n54 + i += n58 } return i, nil } @@ -10631,11 +11348,11 @@ func (m *DeleteMFADeviceResponse) MarshalTo(dAtA []byte) (int, error) { var l int _ = l if m.Response != nil { - nn55, err := m.Response.MarshalTo(dAtA[i:]) + nn59, err := m.Response.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += nn55 + i += nn59 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -10649,11 +11366,11 @@ func (m *DeleteMFADeviceResponse_MFAChallenge) MarshalTo(dAtA []byte) (int, erro dAtA[i] = 0xa i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.MFAChallenge.Size())) - n56, err := m.MFAChallenge.MarshalTo(dAtA[i:]) + n60, err := m.MFAChallenge.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n56 + i += n60 } return i, nil } @@ -10663,11 +11380,11 @@ func (m *DeleteMFADeviceResponse_Ack) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintAuthservice(dAtA, i, uint64(m.Ack.Size())) - n57, err := m.Ack.MarshalTo(dAtA[i:]) + n61, err := m.Ack.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n57 + i += n61 } return i, nil } @@ -10941,6 +11658,24 @@ func (m *Event_DatabaseServer) Size() (n int) { } return n } +func (m *Event_WebSession) Size() (n int) { + var l int + _ = l + if m.WebSession != nil { + l = m.WebSession.Size() + n += 2 + l + sovAuthservice(uint64(l)) + } + return n +} +func (m *Event_WebToken) Size() (n int) { + var l int + _ = l + if m.WebToken != nil { + l = m.WebToken.Size() + n += 2 + l + sovAuthservice(uint64(l)) + } + return n +} func (m *Watch) Size() (n int) { var l int _ = l @@ -10978,6 +11713,10 @@ func (m *WatchKind) Size() (n int) { n += mapEntrySize + 1 + sovAuthservice(uint64(mapEntrySize)) } } + l = len(m.SubKind) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -11590,6 +12329,62 @@ func (m *DeleteAppSessionRequest) Size() (n int) { return n } +func (m *GetWebSessionResponse) Size() (n int) { + var l int + _ = l + if m.Session != nil { + l = m.Session.Size() + n += 1 + l + sovAuthservice(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetWebSessionsResponse) Size() (n int) { + var l int + _ = l + if len(m.Sessions) > 0 { + for _, e := range m.Sessions { + l = e.Size() + n += 1 + l + sovAuthservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetWebTokenResponse) Size() (n int) { + var l int + _ = l + if m.Token != nil { + l = m.Token.Size() + n += 1 + l + sovAuthservice(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetWebTokensResponse) Size() (n int) { + var l int + _ = l + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovAuthservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *GetKubeServicesRequest) Size() (n int) { var l int _ = l @@ -12839,6 +13634,70 @@ func (m *Event) Unmarshal(dAtA []byte) error { } m.Resource = &Event_DatabaseServer{v} iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WebSession", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.WebSessionV2{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Resource = &Event_WebSession{v} + iNdEx = postIndex + case 19: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WebToken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types.WebTokenV3{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Resource = &Event_WebToken{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthservice(dAtA[iNdEx:]) @@ -13168,6 +14027,35 @@ func (m *WatchKind) Unmarshal(dAtA []byte) error { } m.Filter[mapkey] = mapvalue iNdEx = postIndex + case 5: + 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 ErrIntOverflowAuthservice + } + 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 ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubKind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthservice(dAtA[iNdEx:]) @@ -16860,6 +17748,338 @@ func (m *DeleteAppSessionRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *GetWebSessionResponse) 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 ErrIntOverflowAuthservice + } + 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: GetWebSessionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebSessionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Session", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Session == nil { + m.Session = &types.WebSessionV2{} + } + if err := m.Session.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuthservice + } + 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 *GetWebSessionsResponse) 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 ErrIntOverflowAuthservice + } + 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: GetWebSessionsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebSessionsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sessions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sessions = append(m.Sessions, &types.WebSessionV2{}) + if err := m.Sessions[len(m.Sessions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuthservice + } + 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 *GetWebTokenResponse) 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 ErrIntOverflowAuthservice + } + 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: GetWebTokenResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Token == nil { + m.Token = &types.WebTokenV3{} + } + if err := m.Token.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuthservice + } + 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 *GetWebTokensResponse) 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 ErrIntOverflowAuthservice + } + 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: GetWebTokensResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebTokensResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, &types.WebTokenV3{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAuthservice + } + 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 *GetKubeServicesRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -20601,262 +21821,275 @@ var ( ErrIntOverflowAuthservice = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("authservice.proto", fileDescriptor_authservice_a2d5604285d9f75d) } +func init() { proto.RegisterFile("authservice.proto", fileDescriptor_authservice_65caaa95923b9fbe) } -var fileDescriptor_authservice_a2d5604285d9f75d = []byte{ - // 4057 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0xcd, 0x6f, 0x23, 0x47, - 0x76, 0x9f, 0xa6, 0x3e, 0xf9, 0xf4, 0x45, 0x95, 0x38, 0x12, 0x87, 0xd2, 0xa8, 0x67, 0x7b, 0xb2, - 0xc6, 0xd8, 0xeb, 0x48, 0x5e, 0x6a, 0x37, 0x9e, 0xb5, 0xbd, 0x1e, 0x90, 0x94, 0x34, 0xd2, 0x8c, - 0x66, 0x46, 0xdb, 0xa4, 0x38, 0xd9, 0x8d, 0x01, 0x6d, 0x8b, 0x2c, 0x53, 0x0d, 0x51, 0xdd, 0xed, - 0xee, 0xa6, 0x6c, 0x01, 0x39, 0x2c, 0x82, 0xcd, 0x22, 0x08, 0x10, 0x20, 0x97, 0x1c, 0x72, 0x33, - 0x90, 0x5b, 0xae, 0x39, 0xe7, 0x6e, 0x04, 0x08, 0x90, 0x5b, 0x80, 0x1c, 0x98, 0xc4, 0x47, 0xfe, - 0x09, 0x39, 0x05, 0xf5, 0xd5, 0x5d, 0xd5, 0x1f, 0x9a, 0x2f, 0x03, 0x7b, 0x99, 0x51, 0xbf, 0x8f, - 0x5f, 0x55, 0xbd, 0x7a, 0xef, 0x55, 0xbd, 0x7a, 0x84, 0x65, 0x6b, 0x18, 0x9e, 0x07, 0xd8, 0xbf, - 0xb2, 0xbb, 0x78, 0xcb, 0xf3, 0xdd, 0xd0, 0x45, 0x53, 0xf4, 0xbf, 0x6a, 0xb9, 0xef, 0xf6, 0x5d, - 0xfa, 0xe7, 0x36, 0xf9, 0x8b, 0x31, 0xab, 0xeb, 0x7d, 0xd7, 0xed, 0x0f, 0xf0, 0x36, 0xfd, 0x3a, - 0x1b, 0x7e, 0xb9, 0x8d, 0x2f, 0xbd, 0xf0, 0x9a, 0x33, 0xf5, 0x24, 0x33, 0xb4, 0x2f, 0x71, 0x10, - 0x5a, 0x97, 0x1e, 0x17, 0xf8, 0xb8, 0x6f, 0x87, 0xe7, 0xc3, 0xb3, 0xad, 0xae, 0x7b, 0xb9, 0xdd, - 0xf7, 0xad, 0x2b, 0x3b, 0xb4, 0x42, 0xdb, 0x75, 0xac, 0xc1, 0x76, 0x88, 0x07, 0xd8, 0x73, 0xfd, - 0x70, 0xdb, 0xf2, 0xec, 0xed, 0xf0, 0xda, 0xc3, 0x01, 0xfb, 0x97, 0x2b, 0x36, 0xdf, 0x44, 0xf1, - 0x6b, 0xdf, 0xf2, 0x3c, 0xec, 0xc7, 0x7f, 0x70, 0x90, 0x47, 0x6f, 0x02, 0x82, 0xaf, 0xb0, 0x13, - 0x8a, 0xff, 0x18, 0x80, 0xf1, 0xcf, 0x73, 0x30, 0xb5, 0x47, 0x08, 0xe8, 0x21, 0x4c, 0xb6, 0xaf, - 0x3d, 0x5c, 0xd1, 0xee, 0x69, 0x0f, 0x16, 0x6b, 0x25, 0xc6, 0xdf, 0x7a, 0xe1, 0x61, 0x9f, 0x42, - 0x36, 0xd0, 0x78, 0xa4, 0x2f, 0x12, 0xa0, 0x0f, 0xdd, 0x4b, 0x3b, 0xa4, 0x36, 0x32, 0xa9, 0x06, - 0x7a, 0x09, 0x8b, 0x26, 0x0e, 0xdc, 0xa1, 0xdf, 0xc5, 0x07, 0xd8, 0xea, 0x61, 0xbf, 0x52, 0xb8, - 0xa7, 0x3d, 0x98, 0xab, 0xdd, 0xde, 0x62, 0xeb, 0x55, 0x99, 0x8d, 0xd5, 0xf1, 0x48, 0x47, 0x3e, - 0xa7, 0xc5, 0x60, 0x07, 0xb7, 0xcc, 0x04, 0x0c, 0xfa, 0x02, 0x16, 0x9a, 0xd8, 0x0f, 0xeb, 0xc3, - 0xf0, 0xdc, 0xf5, 0xed, 0xf0, 0xba, 0x32, 0x41, 0x71, 0x57, 0x39, 0xae, 0xc2, 0xeb, 0xd4, 0x1a, - 0x1b, 0xe3, 0x91, 0x5e, 0xe9, 0x62, 0x3f, 0x3c, 0xb5, 0x04, 0x55, 0x81, 0x57, 0xc1, 0xd0, 0x9f, - 0xc3, 0x7c, 0x8b, 0x98, 0xab, 0xdb, 0x76, 0x2f, 0xb0, 0x13, 0x54, 0x26, 0x95, 0x49, 0xcb, 0xac, - 0x4e, 0xad, 0xb1, 0x3e, 0x1e, 0xe9, 0x6b, 0x01, 0xa5, 0x9d, 0x86, 0x94, 0xa8, 0x40, 0x2b, 0x48, - 0xe8, 0xb7, 0xb0, 0x78, 0xec, 0xbb, 0x57, 0x76, 0x60, 0xbb, 0x0e, 0x25, 0x55, 0xa6, 0x28, 0xf6, - 0x1a, 0xc7, 0x56, 0x99, 0x9d, 0x5a, 0xe3, 0xee, 0x78, 0xa4, 0xdf, 0xf1, 0x04, 0x95, 0x0d, 0xa0, - 0x5a, 0x46, 0x55, 0x41, 0x6d, 0x98, 0x6b, 0x0e, 0x86, 0x41, 0x88, 0xfd, 0xe7, 0xd6, 0x25, 0xae, - 0x4c, 0x53, 0xf8, 0xb2, 0xb0, 0x4b, 0xcc, 0xe9, 0xd4, 0x1a, 0xd5, 0xf1, 0x48, 0x5f, 0xed, 0x32, - 0xd2, 0xa9, 0x63, 0x5d, 0xaa, 0x26, 0x97, 0x61, 0xa8, 0xbd, 0xd9, 0x67, 0xd3, 0x75, 0xbe, 0xb4, - 0xfb, 0x95, 0x19, 0xd5, 0xde, 0x32, 0xaf, 0xb3, 0xc3, 0xed, 0xcd, 0x91, 0xbb, 0x94, 0x9a, 0xb0, - 0xb7, 0xac, 0x80, 0x3e, 0x86, 0xc9, 0x93, 0x00, 0xfb, 0x95, 0x59, 0x0a, 0xba, 0xc0, 0x41, 0x09, - 0xa9, 0x53, 0x63, 0xde, 0x35, 0x0c, 0xb0, 0xaf, 0x20, 0x50, 0x05, 0xa2, 0x68, 0xba, 0x03, 0x5c, - 0x29, 0x2a, 0x8a, 0x84, 0xd4, 0xd9, 0x61, 0x8a, 0xbe, 0x3b, 0x50, 0x97, 0x45, 0x15, 0xd0, 0x21, - 0x14, 0xc9, 0xba, 0x02, 0xcf, 0xea, 0xe2, 0x0a, 0x50, 0xed, 0x12, 0xd7, 0x8e, 0xe8, 0x8d, 0xb5, - 0xf1, 0x48, 0x5f, 0x71, 0xc4, 0xa7, 0x82, 0x12, 0x6b, 0xa3, 0x47, 0x30, 0xdd, 0xc2, 0xfe, 0x15, - 0xf6, 0x2b, 0x73, 0x14, 0x67, 0x49, 0xb8, 0x09, 0x25, 0x76, 0x6a, 0x8d, 0xf2, 0x78, 0xa4, 0x97, - 0x02, 0xfa, 0xa5, 0x60, 0x70, 0x35, 0x62, 0x5b, 0x13, 0x5f, 0x61, 0x3f, 0xc0, 0xed, 0xa1, 0xe3, - 0xe0, 0x41, 0x65, 0x5e, 0xb1, 0xad, 0xc2, 0x13, 0xbe, 0xec, 0x33, 0xe2, 0x69, 0x48, 0xa9, 0xaa, - 0x6d, 0x15, 0x05, 0x74, 0x0e, 0x25, 0xf6, 0x57, 0xd3, 0x75, 0x1c, 0xdc, 0x25, 0x01, 0x5b, 0x59, - 0xa0, 0x03, 0xdc, 0xe1, 0x03, 0x24, 0xd9, 0x9d, 0x5a, 0x43, 0x1f, 0x8f, 0xf4, 0x75, 0x86, 0x4d, - 0xb6, 0x8f, 0x33, 0x94, 0x61, 0x52, 0xa8, 0x64, 0x1d, 0xf5, 0x6e, 0x17, 0x07, 0x81, 0x89, 0xbf, - 0x1a, 0xe2, 0x20, 0xac, 0x2c, 0x2a, 0xeb, 0x50, 0x78, 0xc2, 0x47, 0x2c, 0x4a, 0x3c, 0xf5, 0x19, - 0x55, 0x5d, 0x87, 0xa2, 0x80, 0x8e, 0x01, 0xea, 0x9e, 0xd7, 0xc2, 0x01, 0x71, 0xf5, 0xca, 0x12, - 0x85, 0x5e, 0xe1, 0xd0, 0x2f, 0xf1, 0x19, 0x67, 0x74, 0x6a, 0x8d, 0x3b, 0xe3, 0x91, 0x7e, 0xdb, - 0xf2, 0xbc, 0xd3, 0x80, 0x91, 0x14, 0x50, 0x09, 0x83, 0xd9, 0xfd, 0xd2, 0x0d, 0x31, 0x77, 0xc6, - 0x4a, 0x29, 0x61, 0x77, 0x89, 0x27, 0xe6, 0xeb, 0x53, 0xe2, 0x29, 0x77, 0xed, 0xa4, 0xdd, 0x25, - 0x05, 0x12, 0xe9, 0xbb, 0x56, 0x68, 0x9d, 0x59, 0x01, 0xe6, 0xee, 0xb1, 0xac, 0x44, 0xba, 0xca, - 0xec, 0xec, 0xb0, 0x48, 0xef, 0x71, 0xea, 0x69, 0x86, 0xbf, 0x24, 0xf0, 0x1a, 0x00, 0xb3, 0x22, - 0x2b, 0x1a, 0x07, 0x30, 0xf5, 0xd2, 0x0a, 0xbb, 0xe7, 0xe8, 0x11, 0x4c, 0x3d, 0xb5, 0x9d, 0x5e, - 0x50, 0xd1, 0xee, 0x4d, 0x50, 0xa7, 0x66, 0xc9, 0x9a, 0x32, 0x09, 0xa3, 0xb1, 0xf6, 0xdd, 0x48, - 0xbf, 0x35, 0x1e, 0xe9, 0x4b, 0x17, 0x44, 0x4c, 0xca, 0xd8, 0x4c, 0xcf, 0xf8, 0xab, 0x02, 0x14, - 0x23, 0x69, 0xb4, 0x01, 0x93, 0xe4, 0x7f, 0x9a, 0xfa, 0x8b, 0x8d, 0xd9, 0xf1, 0x48, 0x9f, 0x24, - 0x7a, 0x26, 0xa5, 0xa2, 0x1a, 0xcc, 0x1d, 0xb9, 0x56, 0xaf, 0x85, 0xbb, 0x3e, 0x0e, 0x03, 0x9a, - 0xdb, 0x67, 0x1b, 0xa5, 0xf1, 0x48, 0x9f, 0x1f, 0xb8, 0x56, 0xef, 0x34, 0x60, 0x74, 0x53, 0x16, - 0x22, 0x88, 0x34, 0x31, 0x4d, 0xc4, 0x88, 0x24, 0xc4, 0x4c, 0x4a, 0x45, 0x4f, 0x60, 0x7a, 0xdf, - 0x1e, 0x90, 0xcd, 0x98, 0xa4, 0xf3, 0xdf, 0x48, 0xce, 0x7f, 0x8b, 0xb1, 0xf7, 0x9c, 0xd0, 0xbf, - 0x66, 0x91, 0xf5, 0x25, 0x25, 0x48, 0x0b, 0xe1, 0x08, 0xd5, 0x5f, 0xc0, 0x9c, 0x24, 0x8c, 0x4a, - 0x30, 0x71, 0x81, 0xaf, 0xd9, 0x4a, 0x4c, 0xf2, 0x27, 0x2a, 0xc3, 0xd4, 0x95, 0x35, 0x18, 0x62, - 0x3a, 0xf1, 0xa2, 0xc9, 0x3e, 0x3e, 0x29, 0x3c, 0xd4, 0x8c, 0x5f, 0xc1, 0x14, 0x39, 0x11, 0x02, - 0x74, 0x1f, 0x26, 0x5a, 0xad, 0x03, 0xaa, 0x34, 0xdf, 0x58, 0x1e, 0x8f, 0xf4, 0x85, 0x20, 0x38, - 0x97, 0xc6, 0x22, 0x5c, 0x22, 0xd4, 0x3e, 0x6a, 0x51, 0x14, 0x2e, 0x14, 0x0e, 0x64, 0xcb, 0x12, - 0xae, 0xf1, 0x2f, 0x93, 0x50, 0x22, 0x39, 0x8b, 0xe2, 0x0a, 0xa7, 0xfe, 0x10, 0x8a, 0xc7, 0xc3, - 0xb3, 0x81, 0xdd, 0x7d, 0xca, 0x67, 0x36, 0xdf, 0x58, 0x1c, 0x8f, 0x74, 0xf0, 0x28, 0xf1, 0xf4, - 0x02, 0x5f, 0x9b, 0xb1, 0x00, 0x7a, 0x00, 0xb3, 0x04, 0x81, 0x98, 0x8b, 0x4d, 0xb9, 0x31, 0x3f, - 0x1e, 0xe9, 0xb3, 0x43, 0x4e, 0x33, 0x23, 0x2e, 0x6a, 0xc1, 0xcc, 0xde, 0x37, 0x9e, 0xed, 0xe3, - 0x80, 0x1f, 0x8c, 0xd5, 0x2d, 0x76, 0x5b, 0xd9, 0x12, 0xb7, 0x95, 0xad, 0xb6, 0xb8, 0xad, 0x34, - 0xee, 0x72, 0x8f, 0x58, 0xc6, 0x4c, 0x25, 0x9e, 0xf9, 0xdf, 0xff, 0xb7, 0xae, 0x99, 0x02, 0x09, - 0x7d, 0x08, 0xd3, 0xfb, 0xae, 0x7f, 0x69, 0x85, 0xf4, 0x3c, 0x2c, 0x72, 0xeb, 0x53, 0x8a, 0x62, - 0x7d, 0x4a, 0x41, 0xfb, 0xb0, 0x68, 0xba, 0xc3, 0x10, 0xb7, 0x5d, 0x11, 0x5e, 0x53, 0x54, 0x6b, - 0x73, 0x3c, 0xd2, 0xab, 0x3e, 0xe1, 0x9c, 0x86, 0x6e, 0x3a, 0x90, 0xcc, 0x84, 0x16, 0xda, 0x83, - 0x45, 0x25, 0x11, 0x04, 0x95, 0xe9, 0x7b, 0x13, 0x0f, 0x8a, 0x2c, 0x5c, 0xd4, 0xf4, 0x21, 0xdb, - 0x3c, 0xa1, 0x84, 0x9e, 0xc3, 0xf2, 0xd3, 0xe1, 0x19, 0xf6, 0x1d, 0x1c, 0xe2, 0x40, 0xcc, 0x68, - 0x86, 0xce, 0xe8, 0xde, 0x78, 0xa4, 0x6f, 0x5c, 0x44, 0xcc, 0x8c, 0x39, 0xa5, 0x55, 0x11, 0x86, - 0x25, 0x3e, 0x51, 0x11, 0x95, 0xfc, 0xf4, 0x5a, 0xe5, 0x1e, 0x9b, 0xe0, 0x36, 0xee, 0x73, 0x2b, - 0xaf, 0x47, 0x6b, 0x17, 0xb1, 0x2e, 0x0d, 0x94, 0xc4, 0x34, 0xfe, 0x53, 0x4b, 0x8d, 0x43, 0xa2, - 0xae, 0xc5, 0xee, 0xb0, 0x34, 0x90, 0x58, 0x68, 0xd2, 0xa8, 0xe3, 0x57, 0x5b, 0x7a, 0x96, 0x9b, - 0xb2, 0x10, 0x71, 0x9d, 0x63, 0x32, 0xad, 0xae, 0x3b, 0x90, 0x5d, 0xc7, 0xe3, 0x34, 0x33, 0xe2, - 0xa2, 0x9a, 0xe4, 0x64, 0x2c, 0x46, 0xe9, 0xad, 0x4c, 0x38, 0x99, 0x34, 0xd9, 0xd8, 0xdd, 0x6a, - 0x30, 0x1b, 0x59, 0x61, 0x32, 0xd6, 0xc9, 0x58, 0x60, 0x24, 0x67, 0x0c, 0x60, 0xf1, 0x31, 0x0e, - 0x09, 0x84, 0x08, 0x06, 0x91, 0x19, 0xb4, 0xcc, 0xcc, 0xf0, 0x19, 0xcc, 0xbd, 0xb4, 0xc3, 0x73, - 0x35, 0xd7, 0xd0, 0x1b, 0xcc, 0xd7, 0x76, 0x78, 0x2e, 0x72, 0x8d, 0x34, 0x94, 0x2c, 0x6e, 0xec, - 0xc1, 0x12, 0x1f, 0x2d, 0x8a, 0xbd, 0x9a, 0x0a, 0xa8, 0xc5, 0xc9, 0x4b, 0x06, 0x54, 0x61, 0x70, - 0xd2, 0x19, 0x51, 0x2b, 0xe5, 0x9e, 0x2c, 0xf1, 0xe6, 0x9d, 0x7a, 0x2b, 0x24, 0xf5, 0x26, 0xdc, - 0x36, 0xe9, 0xac, 0xc6, 0x09, 0x2c, 0x1c, 0x0f, 0x86, 0x7d, 0xdb, 0x21, 0xd6, 0x6a, 0xe1, 0xaf, - 0xd0, 0x2e, 0x40, 0x4c, 0xe0, 0x23, 0x88, 0xc3, 0x2f, 0x66, 0x74, 0x76, 0x1a, 0x4b, 0xe3, 0x91, - 0x3e, 0xe7, 0x51, 0x0a, 0xf5, 0x2f, 0x53, 0xd2, 0x33, 0xfe, 0x76, 0x02, 0x10, 0x1f, 0x83, 0x5c, - 0x4a, 0x71, 0x0b, 0x87, 0xc4, 0x95, 0x57, 0xa1, 0x70, 0xb8, 0xcb, 0xad, 0x3e, 0x3d, 0x1e, 0xe9, - 0x05, 0xbb, 0x67, 0x16, 0x0e, 0x77, 0xd1, 0xcf, 0x60, 0x8a, 0x8a, 0x51, 0x5b, 0x2f, 0x46, 0xe3, - 0xc9, 0x08, 0x8d, 0xe2, 0x78, 0xa4, 0x4f, 0x91, 0xcb, 0x2f, 0x36, 0x99, 0x30, 0xfa, 0x39, 0x14, - 0x77, 0xf1, 0x00, 0xf7, 0xad, 0xd0, 0xf5, 0xb9, 0x03, 0xd1, 0x7b, 0x54, 0x4f, 0x10, 0xa5, 0x2d, - 0x8a, 0x25, 0x49, 0x72, 0x31, 0xb1, 0x15, 0xb8, 0x8e, 0x9c, 0x5c, 0x7c, 0x4a, 0x91, 0x93, 0x0b, - 0x93, 0x41, 0xff, 0xa0, 0xc1, 0x5c, 0xdd, 0x71, 0x5c, 0x56, 0xd3, 0x04, 0xfc, 0x12, 0x7d, 0x7b, - 0x2b, 0xaa, 0x81, 0x8e, 0xac, 0x33, 0x3c, 0xe8, 0x90, 0x7c, 0x1e, 0x34, 0xbe, 0x20, 0x91, 0xf7, - 0x5f, 0x23, 0xfd, 0xd3, 0xb7, 0x29, 0xab, 0xb6, 0xda, 0xbe, 0x65, 0x87, 0x01, 0xbd, 0x53, 0xc4, - 0x03, 0xca, 0x6e, 0x26, 0xcd, 0x03, 0xbd, 0x0f, 0x53, 0xe4, 0x7a, 0x29, 0x72, 0x14, 0xdd, 0x6c, - 0x72, 0x03, 0x55, 0xce, 0x59, 0x2a, 0x61, 0xdc, 0x87, 0x22, 0xb7, 0xe4, 0xe1, 0x6e, 0xde, 0x16, - 0x18, 0xcf, 0xe0, 0x3d, 0xd3, 0xa5, 0xd6, 0xc5, 0x01, 0x0e, 0x8f, 0xad, 0x20, 0xf8, 0xda, 0xf5, - 0x7b, 0xf4, 0xa2, 0xcf, 0x5d, 0x52, 0x78, 0xf3, 0x7d, 0x98, 0xa1, 0xe4, 0x08, 0x86, 0xee, 0x0c, - 0x2d, 0x17, 0x4c, 0xc1, 0x31, 0x9a, 0xb0, 0xf1, 0x18, 0x87, 0x69, 0xac, 0x37, 0x02, 0xf9, 0xbd, - 0x06, 0x7a, 0xd3, 0xc7, 0x99, 0x93, 0x7a, 0xbd, 0x50, 0xde, 0xe0, 0xf5, 0x64, 0x21, 0xe6, 0x12, - 0xa3, 0xf3, 0x9a, 0xf1, 0xc7, 0x30, 0xd1, 0x6e, 0x1f, 0x51, 0xd7, 0x99, 0xa0, 0x16, 0x9c, 0x08, - 0xc3, 0xc1, 0xff, 0x8d, 0xf4, 0xd9, 0xdd, 0x21, 0xab, 0x37, 0x4d, 0xc2, 0x37, 0x16, 0x60, 0xee, - 0xd8, 0x76, 0xfa, 0x7c, 0x44, 0xe3, 0x2f, 0x61, 0x9e, 0x7d, 0x06, 0x9e, 0xeb, 0xb0, 0x24, 0x29, - 0x97, 0x41, 0x52, 0x92, 0x94, 0x0b, 0x1e, 0xb5, 0xc8, 0x79, 0x08, 0x0b, 0xfc, 0x36, 0x86, 0x7d, - 0x7a, 0xcb, 0x64, 0x13, 0xa4, 0x75, 0x04, 0xbb, 0x8f, 0x9d, 0x5e, 0x31, 0x8e, 0xa9, 0x0a, 0x1a, - 0x3f, 0x85, 0x65, 0xe2, 0xca, 0x21, 0x7e, 0xed, 0x7c, 0x66, 0x1c, 0x03, 0xb4, 0xf0, 0xa5, 0xe5, - 0x9d, 0xbb, 0xe4, 0x6c, 0x6d, 0xc8, 0x5f, 0x3c, 0xc0, 0x51, 0x54, 0x48, 0x70, 0x46, 0x67, 0x87, - 0xdd, 0x0e, 0x82, 0x48, 0xd2, 0x94, 0xb4, 0x8c, 0x7f, 0x2f, 0x00, 0xaa, 0x0f, 0x7b, 0x76, 0xd8, - 0x0a, 0x7d, 0x6c, 0x5d, 0x8a, 0x69, 0xfc, 0x02, 0xe6, 0xd9, 0x76, 0x31, 0x32, 0x9d, 0x0e, 0xc9, - 0x1e, 0xec, 0x98, 0x92, 0x59, 0xa4, 0x5a, 0x95, 0xbf, 0x89, 0xaa, 0x89, 0x83, 0xe1, 0xa5, 0x50, - 0x2d, 0x28, 0xaa, 0x32, 0x8b, 0xa8, 0xca, 0xdf, 0xe8, 0x11, 0x2c, 0x36, 0xdd, 0x4b, 0x8f, 0xd8, - 0x84, 0x2b, 0x4f, 0xf0, 0x18, 0xe5, 0xe3, 0x2a, 0x4c, 0x72, 0xbb, 0x55, 0x29, 0xe8, 0x39, 0xac, - 0xec, 0x0f, 0x86, 0xc1, 0x79, 0xdd, 0xe9, 0x35, 0x07, 0x6e, 0x20, 0x50, 0x26, 0xf9, 0x75, 0x86, - 0xa1, 0x64, 0x48, 0x1c, 0xdc, 0x32, 0xb3, 0x14, 0xd1, 0x8f, 0xf9, 0x6b, 0x06, 0xcf, 0x15, 0x0b, - 0x5b, 0xfc, 0xb1, 0xe3, 0x85, 0x83, 0x5f, 0x7c, 0x79, 0x70, 0xcb, 0x64, 0xdc, 0x46, 0x11, 0x66, - 0x84, 0x4b, 0x6d, 0xc3, 0xb2, 0x64, 0x4e, 0x92, 0xdd, 0x86, 0x01, 0xaa, 0xc2, 0xec, 0x89, 0x47, - 0x6e, 0xb7, 0x22, 0x46, 0xcc, 0xe8, 0xdb, 0xf8, 0x50, 0xb5, 0x34, 0xda, 0x80, 0x22, 0xaf, 0x35, - 0x22, 0xe1, 0x98, 0x60, 0x1c, 0xa8, 0xc6, 0xbd, 0x59, 0x5a, 0x19, 0xb7, 0x90, 0x18, 0xb7, 0x94, - 0xb4, 0xb5, 0x71, 0x3b, 0xd3, 0x78, 0xc6, 0xef, 0x34, 0x28, 0x3f, 0xc6, 0x21, 0xad, 0x81, 0x88, - 0xfb, 0x46, 0xd9, 0xe3, 0x27, 0x72, 0x39, 0xcc, 0xfc, 0x75, 0x61, 0x3c, 0xd2, 0x8b, 0x51, 0xf1, - 0x2b, 0x17, 0xbc, 0x9f, 0xc2, 0x62, 0xeb, 0xc2, 0xf6, 0x3a, 0xd6, 0xc0, 0xee, 0xd1, 0x80, 0xe4, - 0x87, 0x31, 0xcd, 0x76, 0xc1, 0x85, 0xed, 0x9d, 0x5e, 0x45, 0x2c, 0x33, 0x21, 0x6a, 0xbc, 0x80, - 0xdb, 0x89, 0x19, 0xf0, 0x80, 0xfd, 0x33, 0x98, 0xe1, 0x24, 0xee, 0xfe, 0xa9, 0x3a, 0x7a, 0x6e, - 0x3c, 0xd2, 0x67, 0x02, 0xae, 0x26, 0x84, 0x8d, 0x67, 0xb0, 0x7a, 0xe2, 0x05, 0xd8, 0x8f, 0x31, - 0xc5, 0xa2, 0x76, 0xa2, 0xc2, 0x5c, 0xcb, 0x2e, 0xcc, 0x61, 0x3c, 0xd2, 0xa7, 0x19, 0xa0, 0x28, - 0xc6, 0x8d, 0x2e, 0xac, 0xb2, 0x48, 0x4e, 0xc1, 0xbd, 0x91, 0x8d, 0x44, 0xec, 0x17, 0x32, 0x63, - 0xff, 0x10, 0xaa, 0x7c, 0x90, 0xc1, 0xe0, 0xdd, 0x36, 0xc3, 0xf8, 0x37, 0x0d, 0xd6, 0x1e, 0x63, - 0x07, 0xfb, 0x16, 0x9d, 0xb2, 0x92, 0x85, 0xe5, 0x7a, 0x41, 0xbb, 0xb1, 0x5e, 0xd0, 0xc5, 0xb9, - 0x55, 0xa0, 0xe7, 0x16, 0x4d, 0xfb, 0xf4, 0xdc, 0xe2, 0xa7, 0x15, 0xba, 0x03, 0x13, 0x27, 0xe6, - 0x21, 0x3f, 0xcf, 0x67, 0x48, 0x52, 0x1e, 0xfa, 0xb6, 0x49, 0x68, 0xe8, 0x30, 0xae, 0x35, 0x26, - 0x5f, 0x59, 0x6b, 0xac, 0xf0, 0x5b, 0xf0, 0x0c, 0xaf, 0x35, 0x94, 0x0a, 0xc3, 0xf8, 0x14, 0x2a, - 0xe9, 0xb5, 0x70, 0xff, 0xd0, 0x61, 0x8a, 0x3d, 0x98, 0xa5, 0x4e, 0x26, 0x46, 0x37, 0x76, 0x63, - 0xdf, 0xa6, 0x41, 0x23, 0xd5, 0x58, 0x89, 0xb8, 0x12, 0x59, 0x94, 0x12, 0x4f, 0xed, 0x9e, 0x1c, - 0x95, 0xad, 0xd8, 0x3f, 0x39, 0x0a, 0x1f, 0xff, 0x13, 0xe2, 0x9f, 0xec, 0xf1, 0x41, 0xcb, 0x7f, - 0x7c, 0xe0, 0x3e, 0xca, 0x54, 0x85, 0x82, 0xf1, 0x12, 0x56, 0x15, 0xd0, 0xd8, 0xeb, 0x7f, 0x09, - 0xb3, 0x82, 0x96, 0xb8, 0xd6, 0x29, 0xb0, 0x74, 0xdf, 0x02, 0xa1, 0x1c, 0xa9, 0x18, 0xdf, 0x6b, - 0xb0, 0xc6, 0x52, 0x4e, 0x7a, 0xdd, 0xaf, 0xbf, 0xfb, 0x0f, 0x61, 0xe1, 0xd8, 0xf2, 0xb1, 0x13, - 0x8a, 0x05, 0x4a, 0xe7, 0x9e, 0x47, 0x19, 0xe2, 0x2d, 0xc5, 0x54, 0x05, 0xd1, 0x36, 0x00, 0x2b, - 0x4f, 0xeb, 0xbd, 0x9e, 0xb8, 0xed, 0xb1, 0x2b, 0x28, 0x2b, 0x60, 0xad, 0x5e, 0xcf, 0x37, 0x25, - 0x91, 0xe4, 0xb1, 0x3c, 0xf9, 0x1a, 0xc7, 0xb2, 0xd1, 0x81, 0x4a, 0x7a, 0x8d, 0x3f, 0xc0, 0xae, - 0x3c, 0x86, 0x35, 0x29, 0xd4, 0xdf, 0xc1, 0x67, 0x2a, 0x74, 0x7b, 0x49, 0x8d, 0xc8, 0x4b, 0x2e, - 0x11, 0xca, 0xc6, 0xaf, 0x48, 0x70, 0x26, 0x38, 0xef, 0x98, 0xef, 0x5e, 0x40, 0x85, 0xe5, 0x3b, - 0x09, 0xf5, 0x9d, 0x32, 0xde, 0x43, 0xa8, 0x30, 0x33, 0x64, 0x00, 0xde, 0x9c, 0xc6, 0x36, 0x61, - 0x23, 0x4a, 0x63, 0x59, 0xab, 0xff, 0x6b, 0x0d, 0xee, 0x3c, 0xc6, 0xa1, 0xfa, 0x6c, 0xf5, 0x47, - 0x38, 0x73, 0xbe, 0x80, 0x6a, 0xd6, 0x34, 0xf8, 0x46, 0x7c, 0x9e, 0xdc, 0x88, 0xdc, 0x17, 0xba, - 0xec, 0x0d, 0xf9, 0x0d, 0xac, 0xb3, 0x0d, 0x51, 0xe5, 0xc5, 0x32, 0x3f, 0x4d, 0xec, 0x49, 0x2e, - 0x7a, 0xd6, 0xde, 0xfc, 0x9d, 0x06, 0xeb, 0xcc, 0xc4, 0xd9, 0xe0, 0x6f, 0x64, 0xc3, 0xfb, 0x30, - 0x7d, 0xe0, 0x92, 0x72, 0x83, 0x6f, 0x27, 0x5d, 0xce, 0xb9, 0x1b, 0x84, 0xc4, 0x9d, 0x39, 0xeb, - 0xe6, 0xe7, 0x39, 0xe3, 0x39, 0xe8, 0xd1, 0x8e, 0xff, 0x00, 0xdb, 0x6a, 0x74, 0x01, 0x09, 0x98, - 0x66, 0xcb, 0x14, 0x10, 0x77, 0x60, 0xa2, 0xd9, 0x32, 0xf9, 0x7b, 0x18, 0x3d, 0x6c, 0xba, 0x81, - 0x6f, 0x12, 0x5a, 0x32, 0x7f, 0x14, 0x5e, 0x27, 0x7f, 0xfc, 0x05, 0xac, 0x28, 0x83, 0xf0, 0x7d, - 0xdf, 0x80, 0xc9, 0x26, 0xf6, 0x43, 0x3e, 0x0c, 0x5d, 0x69, 0x17, 0xfb, 0xa1, 0x49, 0xa9, 0xe8, - 0x3d, 0x98, 0x69, 0xd6, 0xe9, 0x5b, 0x1d, 0x3d, 0x13, 0xe7, 0x59, 0xf2, 0xec, 0x5a, 0xa7, 0x5d, - 0xfa, 0x7e, 0x27, 0x98, 0xc6, 0xdf, 0x68, 0x12, 0x3a, 0x51, 0x7f, 0xf5, 0x1a, 0xb6, 0xc9, 0x5d, - 0x9f, 0xd8, 0x4c, 0x5a, 0x02, 0x4d, 0x9a, 0xbc, 0xc6, 0xa0, 0x2b, 0x90, 0x44, 0x5e, 0xb7, 0x22, - 0xfa, 0x02, 0xca, 0xea, 0x4c, 0x7e, 0xd0, 0x85, 0x5e, 0x40, 0xe5, 0xd9, 0x7e, 0xbd, 0x3e, 0x0c, - 0xcf, 0xb1, 0x13, 0xda, 0x5d, 0x2b, 0xc4, 0xcd, 0x73, 0x6b, 0x30, 0xc0, 0x4e, 0x9f, 0x4e, 0xf0, - 0xa4, 0xb6, 0x1f, 0x1d, 0x60, 0xec, 0x6e, 0x7e, 0x52, 0xdb, 0x8f, 0x24, 0x4c, 0xc2, 0x47, 0x0f, - 0x60, 0xb2, 0xfd, 0xa2, 0x7d, 0xcc, 0xcb, 0x88, 0x32, 0x97, 0x23, 0xa4, 0x58, 0x90, 0x4a, 0x18, - 0xdf, 0xc0, 0x5a, 0x62, 0xb0, 0x68, 0x35, 0xef, 0x89, 0xb1, 0x34, 0x5a, 0x22, 0x45, 0x63, 0x09, - 0x81, 0x83, 0x5b, 0x6c, 0xb0, 0xf7, 0x95, 0xc1, 0x56, 0xa4, 0xc1, 0x24, 0x49, 0x2a, 0xc2, 0x1f, - 0xd2, 0x29, 0xcd, 0xf8, 0x2d, 0xcc, 0xcb, 0x13, 0x27, 0xb7, 0xf2, 0xa7, 0xf8, 0xfa, 0xc0, 0x72, - 0x7a, 0x03, 0x2c, 0x6e, 0xe5, 0x11, 0x81, 0x70, 0x23, 0x51, 0x7e, 0x2d, 0x8f, 0x09, 0xa8, 0x0c, - 0x53, 0x75, 0xcf, 0x3b, 0xdc, 0x65, 0xc1, 0x64, 0xb2, 0x0f, 0xc3, 0x86, 0x39, 0x69, 0xba, 0xaf, - 0x18, 0x60, 0x13, 0xa0, 0x39, 0xb0, 0xb1, 0x43, 0x93, 0x0b, 0x1f, 0x41, 0xa2, 0xd0, 0xa2, 0xc1, - 0xee, 0x3b, 0x56, 0x38, 0xf4, 0x79, 0xcc, 0x9a, 0x31, 0xc1, 0x58, 0x82, 0x05, 0xc5, 0xba, 0x86, - 0x01, 0xf3, 0xb2, 0x05, 0x10, 0x82, 0xc9, 0xa6, 0xdb, 0x13, 0xe3, 0xd2, 0xbf, 0x8d, 0x3f, 0x68, - 0x50, 0x7e, 0xb6, 0x5f, 0x37, 0x71, 0xdf, 0xa6, 0x2d, 0xba, 0x68, 0x39, 0xdb, 0xb2, 0xe5, 0xd7, - 0x65, 0xcb, 0x27, 0x24, 0xc5, 0x16, 0xd4, 0x94, 0x2d, 0xd8, 0x50, 0xb6, 0x20, 0xad, 0xc2, 0xf6, - 0x42, 0xaa, 0xbf, 0x7e, 0xaf, 0xc1, 0x8a, 0x34, 0x91, 0x68, 0xd2, 0x5b, 0xf2, 0x3c, 0xaa, 0xe9, - 0x79, 0x24, 0x3d, 0xe1, 0xa7, 0xca, 0x34, 0xd6, 0x33, 0xa6, 0x71, 0xa3, 0x47, 0x3c, 0x81, 0x72, - 0xd6, 0x22, 0xd5, 0xbd, 0xd7, 0x72, 0xf7, 0xbe, 0x20, 0xef, 0xbd, 0x05, 0x2b, 0x19, 0x13, 0x45, - 0x1f, 0x40, 0x89, 0xd1, 0x58, 0x38, 0xf3, 0x47, 0x3e, 0xa2, 0x97, 0xa2, 0xbf, 0xca, 0x23, 0x8c, - 0x7f, 0xd5, 0xe0, 0x76, 0xa6, 0x89, 0xd1, 0x2a, 0x39, 0x89, 0xba, 0x3e, 0x0e, 0x39, 0x36, 0xff, - 0x22, 0xf4, 0xc3, 0x20, 0x18, 0xf2, 0xe6, 0x7c, 0xd1, 0xe4, 0x5f, 0xe8, 0x4f, 0x60, 0xe1, 0x18, - 0xfb, 0xb6, 0xdb, 0x6b, 0xe1, 0xae, 0xeb, 0xf4, 0x58, 0x2b, 0x61, 0xc1, 0x54, 0x89, 0xc4, 0x0c, - 0xf5, 0x41, 0xdf, 0xf5, 0xed, 0xf0, 0x9c, 0x55, 0xe7, 0x45, 0x33, 0x26, 0x10, 0xec, 0x5d, 0xbb, - 0x6f, 0x87, 0xec, 0x89, 0x6e, 0xc1, 0xe4, 0x5f, 0xa8, 0x02, 0x33, 0xf5, 0x6e, 0xd7, 0x1d, 0x3a, - 0x21, 0xed, 0x50, 0x17, 0x4d, 0xf1, 0x69, 0x7c, 0x00, 0xe5, 0xac, 0xad, 0xc9, 0x74, 0xd5, 0xdf, - 0x15, 0x60, 0xa5, 0xde, 0xeb, 0x3d, 0xdb, 0xaf, 0xef, 0x62, 0xf9, 0xda, 0xf2, 0x33, 0x98, 0x3c, - 0x74, 0xec, 0x90, 0xbb, 0xc8, 0x26, 0xdf, 0xf1, 0x0c, 0x49, 0x22, 0x45, 0x36, 0x9d, 0xfc, 0x8f, - 0x4c, 0x58, 0xd9, 0xfb, 0xc6, 0x0e, 0x42, 0xdb, 0xe9, 0x53, 0xb7, 0x63, 0x03, 0x73, 0xb7, 0x11, - 0x20, 0x39, 0x69, 0xe9, 0xe0, 0x96, 0x99, 0xa5, 0x8c, 0xda, 0xb0, 0xfa, 0x1c, 0x7f, 0x9d, 0xe1, - 0xc5, 0x51, 0x5f, 0x26, 0x82, 0xcd, 0x70, 0xc6, 0x1c, 0x5d, 0x39, 0x48, 0xfe, 0x50, 0x80, 0xb2, - 0xba, 0x30, 0x3e, 0xf2, 0x09, 0x94, 0xa5, 0x09, 0xa9, 0x9e, 0x3a, 0x57, 0xd3, 0xb3, 0x97, 0x23, - 0xc7, 0x63, 0xa6, 0x3a, 0x7a, 0x09, 0x6b, 0xea, 0xa4, 0xd4, 0xfc, 0x17, 0xc7, 0x57, 0x96, 0xc8, - 0xc1, 0x2d, 0x33, 0x4f, 0x1b, 0xd5, 0x60, 0xa2, 0xde, 0xbd, 0xe0, 0x66, 0xc9, 0xde, 0x32, 0xb6, - 0xb2, 0x7a, 0xf7, 0x82, 0x44, 0x76, 0xbd, 0x7b, 0xa1, 0x84, 0xe9, 0x3f, 0x6a, 0xb0, 0x96, 0xb3, - 0xc3, 0x24, 0x66, 0x18, 0x31, 0x7e, 0x8f, 0x33, 0x25, 0x0a, 0xfa, 0xa5, 0xf4, 0x20, 0xb9, 0x58, - 0x7b, 0xff, 0x66, 0x7f, 0xd9, 0x62, 0x94, 0x76, 0xf4, 0x62, 0x69, 0xe8, 0x02, 0x9e, 0xbe, 0x5f, - 0xce, 0xb2, 0x74, 0x53, 0xba, 0x85, 0x66, 0x68, 0xa2, 0x2a, 0x69, 0x46, 0x33, 0x39, 0xb5, 0x68, - 0x25, 0xe8, 0x01, 0x4c, 0x33, 0x22, 0xdf, 0x18, 0xf1, 0x2b, 0x84, 0x58, 0x98, 0xf3, 0x8d, 0x6f, - 0x35, 0xf1, 0x34, 0x91, 0xf2, 0xf7, 0x8f, 0x15, 0x7f, 0xff, 0x11, 0x9f, 0x7f, 0xb6, 0xb0, 0xe2, - 0xf2, 0x0d, 0x98, 0x7b, 0x1b, 0x57, 0x97, 0x95, 0x64, 0x67, 0xfc, 0x27, 0x4d, 0x94, 0x54, 0x69, - 0x7f, 0xdc, 0x83, 0xf9, 0xb7, 0xf3, 0x43, 0x45, 0x0d, 0xfd, 0x9c, 0xb9, 0x49, 0xe1, 0xe6, 0x95, - 0xde, 0xe8, 0x29, 0x9f, 0x89, 0xd7, 0x97, 0xb7, 0xf1, 0x15, 0x63, 0x23, 0x43, 0x3b, 0x1a, 0xce, - 0x58, 0xa5, 0x8f, 0x10, 0x11, 0x2b, 0x2a, 0x85, 0x9a, 0xf4, 0x59, 0x41, 0xa6, 0x47, 0xa9, 0x7f, - 0x86, 0x93, 0xa2, 0x8e, 0x7d, 0xd2, 0x01, 0x84, 0xc0, 0x07, 0x1f, 0x40, 0x31, 0xfa, 0xd1, 0x15, - 0x71, 0xb3, 0xc3, 0xe7, 0x87, 0x6d, 0xe6, 0x66, 0xc7, 0x27, 0xed, 0x92, 0x86, 0x00, 0xa6, 0x77, - 0xf7, 0x8e, 0xf6, 0xda, 0x7b, 0xa5, 0x42, 0xed, 0xdb, 0xbb, 0x30, 0x47, 0x2c, 0xca, 0x6b, 0x32, - 0xf4, 0x19, 0x2c, 0xb6, 0xb0, 0xd3, 0x7b, 0x8a, 0xb1, 0x57, 0x1f, 0xd8, 0x57, 0x38, 0x40, 0x62, - 0xa0, 0x88, 0x54, 0x5d, 0x4d, 0x3d, 0xdc, 0xec, 0x5d, 0x7a, 0xe1, 0xf5, 0x03, 0x0d, 0xfd, 0x04, - 0xe6, 0x68, 0x07, 0x9e, 0xbe, 0x91, 0x06, 0x68, 0x5e, 0xee, 0xca, 0x57, 0xc5, 0x17, 0x65, 0x7e, - 0xa4, 0x91, 0xfb, 0x2d, 0x2b, 0x88, 0x9e, 0xbb, 0x3d, 0x8c, 0x92, 0x35, 0x68, 0x35, 0x35, 0x2e, - 0xfa, 0x04, 0x96, 0xc5, 0xb3, 0x4f, 0xd4, 0x21, 0x47, 0x6b, 0xe2, 0x60, 0x4f, 0xf4, 0xcc, 0xa3, - 0xe1, 0x98, 0xd8, 0x36, 0xcc, 0xf0, 0xc6, 0x1e, 0x12, 0x4f, 0xcb, 0x6a, 0x5b, 0xb1, 0xaa, 0xfe, - 0x9c, 0x08, 0xed, 0xc0, 0xac, 0xe8, 0x04, 0xa2, 0x55, 0x55, 0x23, 0xc8, 0x56, 0xf9, 0x48, 0x43, - 0xfb, 0x64, 0x86, 0x61, 0xa2, 0xf5, 0x57, 0xcd, 0x6a, 0xf1, 0xf1, 0xdf, 0x1e, 0x88, 0xb9, 0x24, - 0x54, 0xf6, 0x60, 0x85, 0x3f, 0x65, 0x28, 0xbf, 0x6d, 0xc9, 0x69, 0x16, 0xe6, 0x6d, 0x08, 0x7a, - 0x04, 0x2b, 0xbc, 0x0c, 0x53, 0x60, 0x4a, 0xd1, 0xc3, 0x3c, 0xef, 0x2b, 0xe5, 0x02, 0x3c, 0x81, - 0xdb, 0xad, 0xc4, 0x7a, 0x58, 0xf7, 0xee, 0x8e, 0x0a, 0x21, 0xb5, 0x09, 0x73, 0xb1, 0xda, 0xec, - 0xc5, 0x8c, 0x62, 0x35, 0x2d, 0xcf, 0x3a, 0xb3, 0x07, 0x76, 0x68, 0xe3, 0x00, 0xdd, 0x53, 0x56, - 0x25, 0xb3, 0x84, 0x9d, 0xef, 0xe4, 0x4a, 0xa0, 0xcf, 0x61, 0xe1, 0x31, 0x0e, 0xe3, 0xe6, 0x25, - 0x5a, 0x4b, 0xb5, 0x3b, 0xb9, 0xa9, 0x45, 0x1d, 0xa1, 0x76, 0x4c, 0x0f, 0xa1, 0x74, 0xe2, 0xf5, - 0xac, 0x10, 0x4b, 0x10, 0x77, 0x53, 0x10, 0x5c, 0xc4, 0xf2, 0xad, 0xcb, 0x20, 0x77, 0x81, 0xdb, - 0x30, 0x79, 0x6c, 0x3b, 0x7d, 0x24, 0x8a, 0x0d, 0xa9, 0xed, 0x54, 0x5d, 0x51, 0x68, 0x3c, 0xa6, - 0x43, 0xd0, 0x5f, 0xd1, 0xb5, 0x43, 0x7f, 0x1a, 0xfd, 0x4a, 0xe0, 0x75, 0xba, 0x7b, 0x55, 0x23, - 0xfe, 0xbd, 0x64, 0xb6, 0x60, 0x67, 0x07, 0xfd, 0x9a, 0xee, 0x43, 0x5a, 0x02, 0xdd, 0x8f, 0xbd, - 0x3c, 0xb7, 0x63, 0x57, 0x5d, 0xcf, 0x1d, 0xa1, 0xb3, 0x83, 0x4e, 0xc5, 0x0b, 0x5c, 0x06, 0xfa, - 0x7b, 0x4a, 0x23, 0xe9, 0x2d, 0x07, 0xd8, 0x01, 0x60, 0xfa, 0x34, 0x90, 0xd5, 0xf0, 0xcb, 0xdd, - 0x97, 0x1d, 0x92, 0x67, 0x7a, 0x6f, 0xa8, 0xf4, 0x39, 0x49, 0xef, 0xa2, 0x53, 0x87, 0x2a, 0xca, - 0x01, 0x22, 0x67, 0x8d, 0x3c, 0xfd, 0x43, 0x28, 0xd5, 0xbb, 0x5f, 0x0d, 0x6d, 0x1f, 0x47, 0x9d, - 0x37, 0xb4, 0x19, 0xb9, 0xb1, 0xca, 0x10, 0x58, 0xb7, 0x93, 0x8d, 0xbc, 0x23, 0x6c, 0x05, 0x18, - 0x1d, 0xc0, 0x5a, 0x94, 0x03, 0x13, 0xac, 0x6c, 0x8d, 0xdc, 0x49, 0xed, 0x41, 0xb9, 0x69, 0x39, - 0x5d, 0x3c, 0x78, 0x37, 0x98, 0x4f, 0x68, 0xcc, 0x49, 0x5d, 0xc9, 0xd5, 0xa4, 0x3e, 0x0f, 0xb9, - 0x65, 0x6e, 0x36, 0x49, 0xb4, 0x0e, 0x4b, 0xcc, 0x88, 0xb1, 0x59, 0xf2, 0xb4, 0xf3, 0x86, 0xff, - 0x18, 0x16, 0xf7, 0x2e, 0xed, 0x90, 0xf6, 0xdc, 0xd8, 0x0f, 0x8f, 0xd5, 0x26, 0x5d, 0xae, 0xe2, - 0x01, 0x2c, 0xf3, 0xac, 0x1a, 0xb7, 0xeb, 0xa2, 0x4c, 0x96, 0xee, 0x88, 0x56, 0xcb, 0x02, 0x56, - 0xee, 0xec, 0x3d, 0xd0, 0x3e, 0xd2, 0xd0, 0x13, 0x6a, 0x81, 0xb8, 0x25, 0x83, 0xd6, 0xe3, 0xd8, - 0x49, 0x35, 0x6a, 0xaa, 0x1b, 0xd9, 0x4c, 0x9e, 0x05, 0x1a, 0xb0, 0x94, 0x68, 0x4c, 0xa1, 0xbb, - 0xe2, 0x4c, 0xcb, 0x6c, 0x58, 0x65, 0x9c, 0x8c, 0x07, 0xc2, 0xaa, 0x69, 0x8c, 0xec, 0x2e, 0x55, - 0xae, 0x8d, 0x8e, 0xa3, 0x23, 0x43, 0x6e, 0x39, 0x21, 0xf5, 0x06, 0x95, 0xd5, 0x8e, 0xca, 0x45, - 0x6c, 0x41, 0x29, 0xd9, 0xac, 0x41, 0x9b, 0x91, 0x45, 0x32, 0x3b, 0x52, 0x55, 0x3d, 0x97, 0xcf, - 0x8d, 0x26, 0x6d, 0x00, 0xeb, 0x30, 0x24, 0x37, 0x40, 0x7e, 0xa6, 0x4f, 0x6d, 0x80, 0xda, 0x1b, - 0x78, 0x4c, 0x7f, 0x61, 0x24, 0x75, 0x5d, 0x50, 0xce, 0x52, 0xaa, 0x77, 0xb3, 0x70, 0xe2, 0x9d, - 0x6c, 0x41, 0x29, 0xd9, 0x80, 0x88, 0x56, 0x9a, 0xd3, 0x7d, 0x89, 0x56, 0x9a, 0xdb, 0xb9, 0x78, - 0x02, 0xa5, 0x64, 0xf7, 0x21, 0x02, 0xcd, 0x69, 0x4b, 0xe4, 0x6e, 0xc5, 0x3e, 0x94, 0xd5, 0x0d, - 0x7c, 0xc5, 0x7a, 0xf3, 0xf3, 0xc8, 0x0a, 0xcb, 0xa8, 0xea, 0x4f, 0x59, 0x73, 0x7e, 0x11, 0x7b, - 0x83, 0xaf, 0x2d, 0x25, 0xba, 0x1e, 0x48, 0xb2, 0x70, 0x46, 0xa7, 0xa0, 0xba, 0x99, 0xc7, 0xe6, - 0xc6, 0x3a, 0x82, 0xe5, 0x54, 0xd3, 0x03, 0xe9, 0x4a, 0x34, 0xa5, 0xbb, 0x17, 0xb9, 0xf3, 0x3b, - 0x12, 0xbf, 0xd6, 0xc8, 0x42, 0xcb, 0xeb, 0x85, 0xdc, 0x74, 0xff, 0xc9, 0xec, 0x82, 0x44, 0xe7, - 0xee, 0x4d, 0x3d, 0x92, 0x5c, 0xd4, 0x5f, 0x03, 0x4a, 0xf7, 0x2c, 0xd0, 0xbd, 0xd8, 0x4e, 0xd9, - 0xcf, 0xef, 0xd5, 0x1f, 0xdd, 0x20, 0x11, 0x19, 0xb3, 0x9c, 0xd5, 0xb0, 0x40, 0x86, 0x62, 0xcf, - 0xcc, 0x86, 0x43, 0x46, 0x8a, 0x32, 0x85, 0xef, 0xe5, 0xa0, 0xdd, 0xd0, 0xbe, 0xc8, 0x5d, 0xfc, - 0x6f, 0x44, 0x4b, 0x2a, 0xdd, 0x66, 0x88, 0xee, 0x1b, 0xaf, 0xe8, 0x43, 0xdc, 0x70, 0x58, 0x2c, - 0xb5, 0xec, 0xbe, 0x23, 0x75, 0x04, 0xa2, 0xa3, 0x22, 0xdd, 0x8a, 0xa8, 0x56, 0xb3, 0x58, 0xdc, - 0x8e, 0x2f, 0x48, 0xad, 0xc7, 0xf2, 0x98, 0xfc, 0xee, 0x8e, 0x52, 0x3a, 0x71, 0x5b, 0xa0, 0xba, - 0x9e, 0xc9, 0xe3, 0x80, 0x4f, 0x61, 0x5e, 0x7e, 0x26, 0x88, 0x80, 0x32, 0x1e, 0x22, 0x22, 0xa0, - 0xac, 0x77, 0x05, 0x7a, 0x94, 0xb5, 0xc5, 0xd1, 0x11, 0xe3, 0xdd, 0xbd, 0xf1, 0x61, 0xa0, 0xba, - 0x79, 0x73, 0x35, 0x2d, 0x1d, 0x90, 0x71, 0x1d, 0x2b, 0xe7, 0xe7, 0x54, 0xd5, 0x2b, 0xe7, 0xe7, - 0x74, 0xe9, 0xdb, 0x28, 0x7d, 0xf7, 0xbf, 0x9b, 0xda, 0x77, 0xdf, 0x6f, 0x6a, 0xff, 0xf1, 0xfd, - 0xa6, 0xf6, 0x3f, 0xdf, 0x6f, 0x6a, 0x67, 0xd3, 0x54, 0x7c, 0xe7, 0xff, 0x03, 0x00, 0x00, 0xff, - 0xff, 0xd0, 0x17, 0x0b, 0x97, 0xa8, 0x35, 0x00, 0x00, +var fileDescriptor_authservice_65caaa95923b9fbe = []byte{ + // 4265 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0x4b, 0x6f, 0x23, 0x49, + 0x72, 0xee, 0xa2, 0x9e, 0x0c, 0xbd, 0xa8, 0x14, 0x5b, 0xa2, 0x28, 0xb5, 0xaa, 0xa7, 0xda, 0x3b, + 0xe8, 0x99, 0x1d, 0x4b, 0xb3, 0xd4, 0x8e, 0xa7, 0x77, 0x66, 0x76, 0x1a, 0x24, 0x25, 0xb5, 0xd4, + 0x4f, 0x6d, 0x91, 0x62, 0x7b, 0xd7, 0x03, 0x68, 0x4b, 0x64, 0x36, 0x55, 0x10, 0x55, 0xc5, 0xa9, + 0x2a, 0xaa, 0x47, 0x80, 0x0f, 0x7b, 0x58, 0x2f, 0x0c, 0x03, 0x06, 0x7c, 0xf1, 0xc1, 0x37, 0x03, + 0xfe, 0x09, 0xf6, 0xd5, 0x57, 0x63, 0x60, 0xc0, 0x80, 0x6f, 0x06, 0x7c, 0xa0, 0xed, 0x3e, 0xf2, + 0x27, 0xf8, 0x64, 0xe4, 0xab, 0x2a, 0xb3, 0x1e, 0x92, 0xfa, 0x01, 0xf8, 0xd2, 0x2d, 0xc6, 0xe3, + 0xcb, 0xcc, 0xc8, 0x88, 0xc8, 0x8c, 0x8c, 0x82, 0x45, 0x6b, 0x10, 0x9c, 0xfa, 0xd8, 0xbb, 0xb0, + 0xdb, 0x78, 0xb3, 0xef, 0xb9, 0x81, 0x8b, 0x26, 0xe8, 0x7f, 0xe5, 0x62, 0xd7, 0xed, 0xba, 0xf4, + 0xcf, 0x2d, 0xf2, 0x17, 0x63, 0x96, 0xd7, 0xba, 0xae, 0xdb, 0xed, 0xe1, 0x2d, 0xfa, 0xeb, 0x64, + 0xf0, 0x6a, 0x0b, 0x9f, 0xf7, 0x83, 0x4b, 0xce, 0xd4, 0xe3, 0xcc, 0xc0, 0x3e, 0xc7, 0x7e, 0x60, + 0x9d, 0xf7, 0xb9, 0xc0, 0x97, 0x5d, 0x3b, 0x38, 0x1d, 0x9c, 0x6c, 0xb6, 0xdd, 0xf3, 0xad, 0xae, + 0x67, 0x5d, 0xd8, 0x81, 0x15, 0xd8, 0xae, 0x63, 0xf5, 0xb6, 0x02, 0xdc, 0xc3, 0x7d, 0xd7, 0x0b, + 0xb6, 0xac, 0xbe, 0xbd, 0x15, 0x5c, 0xf6, 0xb1, 0xcf, 0xfe, 0xe5, 0x8a, 0xf5, 0xb7, 0x51, 0x7c, + 0xed, 0x59, 0xfd, 0x3e, 0xf6, 0xa2, 0x3f, 0x38, 0xc8, 0xc3, 0xb7, 0x01, 0xc1, 0x17, 0xd8, 0x09, + 0xc4, 0x7f, 0x0c, 0xc0, 0xf8, 0x97, 0x59, 0x98, 0xd8, 0x25, 0x04, 0xf4, 0x00, 0xc6, 0x9b, 0x97, + 0x7d, 0x5c, 0xd2, 0xee, 0x6a, 0xf7, 0xe7, 0x2b, 0x05, 0xc6, 0xdf, 0x7c, 0xd1, 0xc7, 0x1e, 0x85, + 0xac, 0xa1, 0xd1, 0x50, 0x9f, 0x27, 0x40, 0x9f, 0xb9, 0xe7, 0x76, 0x40, 0x6d, 0x64, 0x52, 0x0d, + 0xf4, 0x12, 0xe6, 0x4d, 0xec, 0xbb, 0x03, 0xaf, 0x8d, 0xf7, 0xb1, 0xd5, 0xc1, 0x5e, 0x29, 0x77, + 0x57, 0xbb, 0x3f, 0x53, 0xb9, 0xbd, 0xc9, 0xd6, 0xab, 0x32, 0x6b, 0xcb, 0xa3, 0xa1, 0x8e, 0x3c, + 0x4e, 0x8b, 0xc0, 0xf6, 0x6f, 0x99, 0x31, 0x18, 0xf4, 0x1d, 0xcc, 0xd5, 0xb1, 0x17, 0x54, 0x07, + 0xc1, 0xa9, 0xeb, 0xd9, 0xc1, 0x65, 0x69, 0x8c, 0xe2, 0x2e, 0x73, 0x5c, 0x85, 0xd7, 0xaa, 0xd4, + 0xd6, 0x47, 0x43, 0xbd, 0xd4, 0xc6, 0x5e, 0x70, 0x6c, 0x09, 0xaa, 0x02, 0xaf, 0x82, 0xa1, 0x3f, + 0x85, 0xd9, 0x06, 0x31, 0x57, 0xbb, 0xe9, 0x9e, 0x61, 0xc7, 0x2f, 0x8d, 0x2b, 0x93, 0x96, 0x59, + 0xad, 0x4a, 0x6d, 0x6d, 0x34, 0xd4, 0x57, 0x7c, 0x4a, 0x3b, 0x0e, 0x28, 0x51, 0x81, 0x56, 0x90, + 0xd0, 0x6f, 0x61, 0xfe, 0xd0, 0x73, 0x2f, 0x6c, 0xdf, 0x76, 0x1d, 0x4a, 0x2a, 0x4d, 0x50, 0xec, + 0x15, 0x8e, 0xad, 0x32, 0x5b, 0x95, 0xda, 0x9d, 0xd1, 0x50, 0x5f, 0xed, 0x0b, 0x2a, 0x1b, 0x40, + 0xb5, 0x8c, 0xaa, 0x82, 0x9a, 0x30, 0x53, 0xef, 0x0d, 0xfc, 0x00, 0x7b, 0xcf, 0xad, 0x73, 0x5c, + 0x9a, 0xa4, 0xf0, 0x45, 0x61, 0x97, 0x88, 0xd3, 0xaa, 0xd4, 0xca, 0xa3, 0xa1, 0xbe, 0xdc, 0x66, + 0xa4, 0x63, 0xc7, 0x3a, 0x57, 0x4d, 0x2e, 0xc3, 0x50, 0x7b, 0xb3, 0x9f, 0x75, 0xd7, 0x79, 0x65, + 0x77, 0x4b, 0x53, 0xaa, 0xbd, 0x65, 0x5e, 0x6b, 0x9b, 0xdb, 0x9b, 0x23, 0xb7, 0x29, 0x35, 0x66, + 0x6f, 0x59, 0x01, 0x7d, 0x09, 0xe3, 0x47, 0x3e, 0xf6, 0x4a, 0xd3, 0x14, 0x74, 0x8e, 0x83, 0x12, + 0x52, 0xab, 0xc2, 0xbc, 0x6b, 0xe0, 0x63, 0x4f, 0x41, 0xa0, 0x0a, 0x44, 0xd1, 0x74, 0x7b, 0xb8, + 0x94, 0x57, 0x14, 0x09, 0xa9, 0xb5, 0xcd, 0x14, 0x3d, 0xb7, 0xa7, 0x2e, 0x8b, 0x2a, 0xa0, 0x03, + 0xc8, 0x93, 0x75, 0xf9, 0x7d, 0xab, 0x8d, 0x4b, 0x40, 0xb5, 0x0b, 0x5c, 0x3b, 0xa4, 0xd7, 0x56, + 0x46, 0x43, 0x7d, 0xc9, 0x11, 0x3f, 0x15, 0x94, 0x48, 0x1b, 0x3d, 0x84, 0xc9, 0x06, 0xf6, 0x2e, + 0xb0, 0x57, 0x9a, 0xa1, 0x38, 0x0b, 0xc2, 0x4d, 0x28, 0xb1, 0x55, 0xa9, 0x15, 0x47, 0x43, 0xbd, + 0xe0, 0xd3, 0x5f, 0x0a, 0x06, 0x57, 0x23, 0xb6, 0x35, 0xf1, 0x05, 0xf6, 0x7c, 0xdc, 0x1c, 0x38, + 0x0e, 0xee, 0x95, 0x66, 0x15, 0xdb, 0x2a, 0x3c, 0xe1, 0xcb, 0x1e, 0x23, 0x1e, 0x07, 0x94, 0xaa, + 0xda, 0x56, 0x51, 0x40, 0xa7, 0x50, 0x60, 0x7f, 0xd5, 0x5d, 0xc7, 0xc1, 0x6d, 0x12, 0xb0, 0xa5, + 0x39, 0x3a, 0xc0, 0x2a, 0x1f, 0x20, 0xce, 0x6e, 0x55, 0x6a, 0xfa, 0x68, 0xa8, 0xaf, 0x31, 0x6c, + 0xb2, 0x7d, 0x9c, 0xa1, 0x0c, 0x93, 0x40, 0x25, 0xeb, 0xa8, 0xb6, 0xdb, 0xd8, 0xf7, 0x4d, 0xfc, + 0xfd, 0x00, 0xfb, 0x41, 0x69, 0x5e, 0x59, 0x87, 0xc2, 0x13, 0x3e, 0x62, 0x51, 0xe2, 0xb1, 0xc7, + 0xa8, 0xea, 0x3a, 0x14, 0x05, 0x74, 0x08, 0x50, 0xed, 0xf7, 0x1b, 0xd8, 0x27, 0xae, 0x5e, 0x5a, + 0xa0, 0xd0, 0x4b, 0x1c, 0xfa, 0x25, 0x3e, 0xe1, 0x8c, 0x56, 0xa5, 0xb6, 0x3a, 0x1a, 0xea, 0xb7, + 0xad, 0x7e, 0xff, 0xd8, 0x67, 0x24, 0x05, 0x54, 0xc2, 0x60, 0x76, 0x3f, 0x77, 0x03, 0xcc, 0x9d, + 0xb1, 0x54, 0x88, 0xd9, 0x5d, 0xe2, 0x89, 0xf9, 0x7a, 0x94, 0x78, 0xcc, 0x5d, 0x3b, 0x6e, 0x77, + 0x49, 0x81, 0x44, 0xfa, 0x8e, 0x15, 0x58, 0x27, 0x96, 0x8f, 0xb9, 0x7b, 0x2c, 0x2a, 0x91, 0xae, + 0x32, 0x5b, 0xdb, 0x2c, 0xd2, 0x3b, 0x9c, 0x7a, 0x9c, 0xe2, 0x2f, 0x31, 0x3c, 0x62, 0x91, 0x68, + 0xe1, 0x25, 0x74, 0x8d, 0x45, 0x5e, 0xe3, 0x93, 0x74, 0x8b, 0x44, 0xa2, 0x68, 0x1f, 0xa6, 0x5f, + 0xe2, 0x13, 0x96, 0x97, 0x96, 0x28, 0xde, 0x62, 0x84, 0xc7, 0x32, 0xd2, 0x36, 0x8b, 0x0a, 0x82, + 0x96, 0xcc, 0x45, 0xa1, 0x76, 0x0d, 0x60, 0x5a, 0x64, 0x6c, 0x63, 0x1f, 0x26, 0x5e, 0x5a, 0x41, + 0xfb, 0x14, 0x3d, 0x84, 0x89, 0x27, 0xb6, 0xd3, 0xf1, 0x4b, 0xda, 0xdd, 0x31, 0x1a, 0x70, 0xec, + 0x20, 0xa1, 0x4c, 0xc2, 0xa8, 0xad, 0xfc, 0x38, 0xd4, 0x6f, 0x8d, 0x86, 0xfa, 0xc2, 0x19, 0x11, + 0x93, 0x4e, 0x13, 0xa6, 0x67, 0xfc, 0x53, 0x0e, 0xf2, 0xa1, 0x34, 0x5a, 0x87, 0x71, 0xf2, 0x3f, + 0x3d, 0x96, 0xf2, 0xb5, 0xe9, 0xd1, 0x50, 0x1f, 0x27, 0x7a, 0x26, 0xa5, 0xa2, 0x0a, 0xcc, 0x3c, + 0x75, 0xad, 0x4e, 0x03, 0xb7, 0x3d, 0x1c, 0xf8, 0xf4, 0xdc, 0x99, 0xae, 0x15, 0x46, 0x43, 0x7d, + 0xb6, 0xe7, 0x5a, 0x9d, 0x63, 0x9f, 0xd1, 0x4d, 0x59, 0x88, 0x20, 0xd2, 0xa4, 0x39, 0x16, 0x21, + 0x92, 0xf0, 0x37, 0x29, 0x15, 0x3d, 0x86, 0xc9, 0x3d, 0xbb, 0x47, 0x1c, 0x65, 0x9c, 0xce, 0x7f, + 0x3d, 0x3e, 0xff, 0x4d, 0xc6, 0xde, 0x75, 0x02, 0xef, 0x92, 0x45, 0xfd, 0x2b, 0x4a, 0x90, 0x16, + 0xc2, 0x11, 0xd0, 0xe7, 0x30, 0xd5, 0x18, 0x9c, 0xd0, 0xe9, 0x4f, 0xd0, 0xc1, 0xe8, 0xd1, 0xe7, + 0x0f, 0x4e, 0x8e, 0xc9, 0x12, 0x24, 0x05, 0x21, 0x56, 0xfe, 0x05, 0xcc, 0x48, 0xf0, 0xa8, 0x00, + 0x63, 0x67, 0xf8, 0x92, 0xad, 0xdd, 0x24, 0x7f, 0xa2, 0x22, 0x4c, 0x5c, 0x58, 0xbd, 0x01, 0xa6, + 0x4b, 0xcd, 0x9b, 0xec, 0xc7, 0x57, 0xb9, 0x07, 0x9a, 0xf1, 0x2b, 0x98, 0x20, 0xe7, 0x9b, 0x8f, + 0xee, 0xc1, 0x58, 0xa3, 0xb1, 0x4f, 0x95, 0x66, 0x6b, 0x8b, 0xa3, 0xa1, 0x3e, 0xe7, 0xfb, 0xa7, + 0xd2, 0x60, 0x84, 0x4b, 0x84, 0x9a, 0x4f, 0x1b, 0x14, 0x85, 0x0b, 0x05, 0x3d, 0x79, 0x2f, 0x08, + 0xd7, 0xf8, 0xc7, 0x71, 0x28, 0x90, 0x0c, 0x4c, 0x71, 0x45, 0x88, 0x7e, 0x06, 0xf9, 0xc3, 0xc1, + 0x49, 0xcf, 0x6e, 0x3f, 0xe1, 0x33, 0x9b, 0xad, 0xcd, 0x8f, 0x86, 0x3a, 0xf4, 0x29, 0xf1, 0xf8, + 0x0c, 0x5f, 0x9a, 0x91, 0x00, 0xba, 0x0f, 0xd3, 0x04, 0x81, 0x18, 0x98, 0x4d, 0xb9, 0x36, 0x3b, + 0x1a, 0xea, 0xd3, 0x03, 0x4e, 0x33, 0x43, 0x2e, 0x6a, 0xc0, 0xd4, 0xee, 0x0f, 0x7d, 0xdb, 0xc3, + 0x3e, 0x3f, 0xe6, 0xcb, 0x9b, 0xec, 0xee, 0xb5, 0x29, 0xee, 0x5e, 0x9b, 0x4d, 0x71, 0xf7, 0xaa, + 0xdd, 0xe1, 0x3e, 0xb4, 0x88, 0x99, 0x4a, 0x34, 0xf3, 0xbf, 0xf9, 0x2f, 0x5d, 0x33, 0x05, 0x12, + 0xfa, 0x0c, 0x26, 0xf7, 0x5c, 0xef, 0xdc, 0x0a, 0xe8, 0xe9, 0x9e, 0xe7, 0xfb, 0x45, 0x29, 0xca, + 0x7e, 0x51, 0x0a, 0xda, 0x83, 0x79, 0xd3, 0x1d, 0x04, 0xb8, 0xe9, 0x8a, 0x64, 0xc1, 0xb6, 0x6d, + 0x63, 0x34, 0xd4, 0xcb, 0x1e, 0xe1, 0x1c, 0x07, 0x6e, 0x32, 0x2d, 0x98, 0x31, 0x2d, 0xb4, 0x0b, + 0xf3, 0x4a, 0x5a, 0xf3, 0x4b, 0x93, 0x77, 0xc7, 0xee, 0xe7, 0x59, 0xf0, 0xab, 0xc9, 0x50, 0xb6, + 0x79, 0x4c, 0x09, 0x3d, 0x87, 0xc5, 0x27, 0x83, 0x13, 0xec, 0x39, 0x38, 0xc0, 0xbe, 0x98, 0xd1, + 0x14, 0x9d, 0xd1, 0xdd, 0xd1, 0x50, 0x5f, 0x3f, 0x0b, 0x99, 0x29, 0x73, 0x4a, 0xaa, 0x22, 0x0c, + 0x0b, 0x7c, 0xa2, 0x22, 0xc7, 0xf0, 0xb3, 0x78, 0x99, 0xfb, 0x78, 0x8c, 0x5b, 0xbb, 0xc7, 0xad, + 0xbc, 0x16, 0xae, 0x5d, 0x64, 0x2e, 0x69, 0xa0, 0x38, 0xa6, 0xf1, 0x1f, 0x5a, 0x62, 0x1c, 0x12, + 0xa7, 0x0d, 0x76, 0x23, 0xa7, 0xa1, 0xc7, 0x82, 0x99, 0xc6, 0x29, 0xbf, 0xa8, 0xd3, 0x9b, 0x89, + 0x29, 0x0b, 0x11, 0xd7, 0x39, 0x24, 0xd3, 0x6a, 0xbb, 0x3d, 0xd9, 0x75, 0xfa, 0x9c, 0x66, 0x86, + 0x5c, 0x54, 0x91, 0x9c, 0x6c, 0x2c, 0x0a, 0x34, 0xe1, 0x64, 0xd2, 0x64, 0x23, 0x77, 0xab, 0xc0, + 0x74, 0x68, 0x85, 0xf1, 0x48, 0x27, 0x65, 0x81, 0xa1, 0x9c, 0xd1, 0x83, 0xf9, 0x47, 0x38, 0x20, + 0x10, 0x22, 0x18, 0x44, 0x2e, 0xd1, 0x52, 0x73, 0xc9, 0x37, 0x30, 0xf3, 0xd2, 0x0e, 0x4e, 0xd5, + 0xec, 0x44, 0xef, 0x63, 0xaf, 0xed, 0xe0, 0x54, 0x64, 0x27, 0x69, 0x28, 0x59, 0xdc, 0xd8, 0x85, + 0x05, 0x3e, 0x5a, 0x18, 0x7b, 0x15, 0x15, 0x50, 0x8b, 0xd2, 0x9d, 0x0c, 0xa8, 0xc2, 0xe0, 0xb8, + 0x33, 0xa2, 0x46, 0xc2, 0x3d, 0x59, 0xaa, 0xce, 0x3a, 0xc3, 0x97, 0x48, 0xb2, 0x8e, 0xb9, 0x6d, + 0xdc, 0x59, 0x8d, 0x23, 0x98, 0x3b, 0xec, 0x0d, 0xba, 0xb6, 0x43, 0xac, 0xd5, 0xc0, 0xdf, 0xa3, + 0x1d, 0x80, 0x88, 0xc0, 0x47, 0x10, 0x07, 0x57, 0xc4, 0x68, 0x6d, 0xd7, 0x16, 0x46, 0x43, 0x7d, + 0xa6, 0x4f, 0x29, 0xd4, 0xbf, 0x4c, 0x49, 0xcf, 0xf8, 0xab, 0x31, 0x40, 0x7c, 0x0c, 0x72, 0xc5, + 0xc6, 0x0d, 0x1c, 0x10, 0x57, 0x5e, 0x86, 0xdc, 0xc1, 0x0e, 0xb7, 0xfa, 0xe4, 0x68, 0xa8, 0xe7, + 0xec, 0x8e, 0x99, 0x3b, 0xd8, 0x41, 0x3f, 0x87, 0x09, 0x2a, 0x46, 0x6d, 0x3d, 0x1f, 0x8e, 0x27, + 0x23, 0xd4, 0xf2, 0xa3, 0xa1, 0x3e, 0x41, 0xae, 0xf2, 0xd8, 0x64, 0xc2, 0xe8, 0x0b, 0xc8, 0xef, + 0xe0, 0x1e, 0xee, 0x5a, 0x81, 0xeb, 0x71, 0x07, 0xa2, 0xe7, 0x5f, 0x47, 0x10, 0xa5, 0x2d, 0x8a, + 0x24, 0x49, 0x72, 0x31, 0xb1, 0xe5, 0xbb, 0x8e, 0x9c, 0x5c, 0x3c, 0x4a, 0x91, 0x93, 0x0b, 0x93, + 0x41, 0x7f, 0xab, 0xc1, 0x4c, 0xd5, 0x71, 0x5c, 0x56, 0xa1, 0xf9, 0xbc, 0x24, 0xb8, 0xbd, 0x19, + 0x56, 0x74, 0x4f, 0xad, 0x13, 0xdc, 0x6b, 0x91, 0x7c, 0xee, 0xd7, 0xbe, 0x23, 0x91, 0xf7, 0x9f, + 0x43, 0xfd, 0xeb, 0x77, 0x29, 0x12, 0x37, 0x9b, 0x9e, 0x65, 0x07, 0x3e, 0xbd, 0x21, 0x45, 0x03, + 0xca, 0x6e, 0x26, 0xcd, 0x03, 0x7d, 0x02, 0x13, 0xe4, 0xb2, 0x2c, 0x72, 0x14, 0xdd, 0x6c, 0x72, + 0x9f, 0x56, 0x4e, 0x66, 0x2a, 0x61, 0xdc, 0x83, 0x3c, 0xb7, 0xe4, 0xc1, 0x4e, 0xd6, 0x16, 0x18, + 0xcf, 0xe0, 0x63, 0xd3, 0xa5, 0xd6, 0xc5, 0x3e, 0x0e, 0x0e, 0x2d, 0xdf, 0x7f, 0xed, 0x7a, 0x1d, + 0x7a, 0x61, 0xe0, 0x2e, 0x29, 0xbc, 0xf9, 0x1e, 0x4c, 0x51, 0x72, 0x08, 0x43, 0x77, 0x86, 0x5e, + 0x38, 0x4c, 0xc1, 0x31, 0xea, 0xb0, 0xfe, 0x08, 0x07, 0x49, 0xac, 0xb7, 0x02, 0xf9, 0xbd, 0x06, + 0x7a, 0xdd, 0xc3, 0xa9, 0x93, 0xba, 0x59, 0x28, 0xaf, 0xf3, 0xea, 0x38, 0x17, 0x71, 0x89, 0xd1, + 0x79, 0x05, 0xfc, 0x13, 0x18, 0x6b, 0x36, 0x9f, 0x52, 0xd7, 0x19, 0xa3, 0x16, 0x1c, 0x0b, 0x82, + 0xde, 0xff, 0x0e, 0xf5, 0xe9, 0x9d, 0x01, 0xab, 0x9e, 0x4d, 0xc2, 0x37, 0xe6, 0x60, 0xe6, 0xd0, + 0x76, 0xba, 0x7c, 0x44, 0xe3, 0xcf, 0x61, 0x96, 0xfd, 0xf4, 0xfb, 0xae, 0xc3, 0x92, 0xa4, 0x5c, + 0xd4, 0x49, 0x49, 0x52, 0x2e, 0xdf, 0xd4, 0x92, 0xed, 0x01, 0xcc, 0xf1, 0xbb, 0x25, 0xf6, 0xe8, + 0x0d, 0x91, 0x4d, 0x90, 0x56, 0x45, 0xec, 0x76, 0x79, 0x7c, 0xc1, 0x38, 0xa6, 0x2a, 0x68, 0xfc, + 0x0c, 0x16, 0x89, 0x2b, 0x07, 0xf8, 0xc6, 0xf9, 0xcc, 0x38, 0x04, 0x68, 0xe0, 0x73, 0xab, 0x7f, + 0xea, 0x92, 0xb3, 0xb5, 0x26, 0xff, 0xe2, 0x01, 0x8e, 0xc2, 0xb2, 0x88, 0x33, 0x5a, 0xdb, 0xec, + 0x76, 0xe0, 0x87, 0x92, 0xa6, 0xa4, 0x65, 0xfc, 0x5b, 0x0e, 0x50, 0x75, 0xd0, 0xb1, 0x83, 0x46, + 0xe0, 0x61, 0xeb, 0x5c, 0x4c, 0xe3, 0x17, 0x30, 0xcb, 0xb6, 0x8b, 0x91, 0xe9, 0x74, 0x48, 0xf6, + 0x60, 0xc7, 0x94, 0xcc, 0x22, 0xb5, 0xb7, 0xfc, 0x9b, 0xa8, 0x9a, 0xd8, 0x1f, 0x9c, 0x0b, 0xd5, + 0x9c, 0xa2, 0x2a, 0xb3, 0x88, 0xaa, 0xfc, 0x1b, 0x3d, 0x84, 0xf9, 0xba, 0x7b, 0xde, 0x27, 0x36, + 0xe1, 0xca, 0x63, 0x3c, 0x46, 0xf9, 0xb8, 0x0a, 0x93, 0xdc, 0xd5, 0x55, 0x0a, 0x7a, 0x0e, 0x4b, + 0x7b, 0xbd, 0x81, 0x7f, 0x5a, 0x75, 0x3a, 0xf5, 0x9e, 0xeb, 0x0b, 0x94, 0x71, 0x7e, 0x9d, 0x61, + 0x28, 0x29, 0x12, 0xfb, 0xb7, 0xcc, 0x34, 0x45, 0xf4, 0x13, 0xfe, 0x36, 0xc3, 0x73, 0xc5, 0xdc, + 0x26, 0x7f, 0xba, 0x79, 0xe1, 0xe0, 0x17, 0xaf, 0xf6, 0x6f, 0x99, 0x8c, 0x5b, 0xcb, 0xc3, 0x94, + 0x70, 0xa9, 0x2d, 0x58, 0x94, 0xcc, 0x49, 0xb2, 0xdb, 0xc0, 0x47, 0x65, 0x98, 0x3e, 0xea, 0x93, + 0xfb, 0xb0, 0x88, 0x11, 0x33, 0xfc, 0x6d, 0x7c, 0xa6, 0x5a, 0x1a, 0xad, 0x43, 0x9e, 0xd7, 0x09, + 0xa1, 0x70, 0x44, 0x30, 0xf6, 0x55, 0xe3, 0x5e, 0x2d, 0xad, 0x8c, 0x9b, 0x8b, 0x8d, 0x5b, 0x88, + 0xdb, 0xda, 0xb8, 0x9d, 0x6a, 0x3c, 0xe3, 0x77, 0x1a, 0x14, 0x1f, 0xe1, 0x80, 0x56, 0x74, 0xc4, + 0x7d, 0xc3, 0xec, 0xf1, 0x53, 0xb9, 0xb8, 0x67, 0xfe, 0x3a, 0x37, 0x1a, 0xea, 0xf9, 0xb0, 0x94, + 0x97, 0xcb, 0xf7, 0xaf, 0x61, 0xbe, 0x71, 0x66, 0xf7, 0x5b, 0x56, 0xcf, 0xee, 0xd0, 0x80, 0xe4, + 0x87, 0x31, 0xcd, 0x76, 0xfe, 0x99, 0xdd, 0x3f, 0xbe, 0x08, 0x59, 0x66, 0x4c, 0xd4, 0x78, 0x01, + 0xb7, 0x63, 0x33, 0xe0, 0x01, 0xfb, 0x27, 0x30, 0xc5, 0x49, 0xdc, 0xfd, 0x13, 0xaf, 0x02, 0x33, + 0xa3, 0xa1, 0x3e, 0xe5, 0x73, 0x35, 0x21, 0x6c, 0x3c, 0x83, 0xe5, 0xa3, 0xbe, 0x8f, 0xbd, 0x08, + 0x53, 0x2c, 0x6a, 0x3b, 0x7c, 0x66, 0xd0, 0xd2, 0x9f, 0x19, 0x60, 0x34, 0xd4, 0x27, 0x19, 0xa0, + 0x78, 0x5a, 0x30, 0xda, 0xb0, 0xcc, 0x22, 0x39, 0x01, 0xf7, 0x56, 0x36, 0x12, 0xb1, 0x9f, 0x4b, + 0x8d, 0xfd, 0x03, 0x28, 0xf3, 0x41, 0x7a, 0xbd, 0xf7, 0xdb, 0x0c, 0xe3, 0x5f, 0x35, 0x58, 0x79, + 0x84, 0x1d, 0xec, 0x59, 0x74, 0xca, 0x4a, 0x16, 0x96, 0xeb, 0x05, 0xed, 0xca, 0x7a, 0x41, 0x17, + 0xe7, 0x56, 0x8e, 0x9e, 0x5b, 0x34, 0xed, 0xd3, 0x73, 0x8b, 0x9f, 0x56, 0x68, 0x15, 0xc6, 0x8e, + 0xcc, 0x03, 0x7e, 0x9e, 0x4f, 0x91, 0xa4, 0x3c, 0xf0, 0x6c, 0x93, 0xd0, 0xd0, 0x41, 0x54, 0x6b, + 0x8c, 0x5f, 0x5b, 0x6b, 0x2c, 0xf1, 0x5b, 0xf0, 0x14, 0xaf, 0x35, 0x94, 0x0a, 0xc3, 0xf8, 0x1a, + 0x4a, 0xc9, 0xb5, 0x70, 0xff, 0xd0, 0x61, 0x82, 0x95, 0xd9, 0x89, 0x93, 0x89, 0xd1, 0x8d, 0x9d, + 0xc8, 0xb7, 0x69, 0xd0, 0x48, 0x35, 0x56, 0x2c, 0xae, 0x44, 0x16, 0xa5, 0xc4, 0x63, 0xbb, 0x23, + 0x47, 0x65, 0x23, 0xf2, 0x4f, 0x8e, 0xc2, 0xc7, 0xff, 0x8a, 0xf8, 0x27, 0x7b, 0x38, 0xd0, 0xb2, + 0x1f, 0x0e, 0xb8, 0x8f, 0x32, 0x55, 0xa1, 0x60, 0xbc, 0x84, 0x65, 0x05, 0x34, 0xf2, 0xfa, 0x5f, + 0xc2, 0xb4, 0xa0, 0xc5, 0xae, 0x75, 0x0a, 0x2c, 0xdd, 0x37, 0x5f, 0x28, 0x87, 0x2a, 0xc6, 0x1b, + 0x0d, 0x56, 0x58, 0xca, 0x49, 0xae, 0xfb, 0xe6, 0xbb, 0xff, 0x00, 0xe6, 0x0e, 0x2d, 0x0f, 0x3b, + 0x81, 0x58, 0xa0, 0x74, 0xee, 0xf5, 0x29, 0x43, 0xbc, 0x83, 0x98, 0xaa, 0x20, 0xda, 0x02, 0x60, + 0xe5, 0x69, 0xb5, 0xd3, 0x11, 0xb7, 0x3d, 0x76, 0x05, 0x65, 0x05, 0xac, 0xd5, 0xe9, 0x78, 0xa6, + 0x24, 0x12, 0x3f, 0x96, 0xc7, 0x6f, 0x70, 0x2c, 0x1b, 0x2d, 0x28, 0x25, 0xd7, 0xf8, 0x01, 0x76, + 0xe5, 0x11, 0xac, 0x48, 0xa1, 0xfe, 0xde, 0x3e, 0x13, 0x8d, 0xf8, 0x01, 0x7d, 0x26, 0x12, 0xfc, + 0x60, 0x3e, 0x73, 0x00, 0x4b, 0x0c, 0x58, 0x8d, 0xaf, 0x8a, 0x1c, 0x5f, 0xa9, 0xcf, 0x58, 0xc9, + 0x90, 0x7b, 0x46, 0x43, 0x4e, 0x88, 0x44, 0x33, 0xfc, 0x02, 0x26, 0x79, 0x1f, 0x80, 0xcd, 0x2f, + 0x05, 0x8c, 0xe6, 0x5e, 0xf6, 0xf8, 0x6f, 0x72, 0x61, 0xa3, 0x44, 0x97, 0x4c, 0x6a, 0x6d, 0x5e, + 0xba, 0x8a, 0x94, 0x68, 0xfc, 0x8a, 0x24, 0xb9, 0x18, 0xe7, 0x3d, 0xcf, 0x8d, 0x17, 0x50, 0x62, + 0xe7, 0x86, 0x84, 0xfa, 0x5e, 0x27, 0xc7, 0x03, 0x28, 0x31, 0x77, 0x4a, 0x01, 0xbc, 0xfa, 0x38, + 0xd8, 0x80, 0xf5, 0xf0, 0x38, 0x48, 0x5b, 0xfd, 0x5f, 0x68, 0xb0, 0xfa, 0x08, 0x07, 0xea, 0x63, + 0xe6, 0xff, 0xc3, 0xd9, 0xfd, 0x1d, 0x94, 0xd3, 0xa6, 0xc1, 0x37, 0xe2, 0xdb, 0xf8, 0x46, 0x64, + 0xbe, 0xdb, 0xa6, 0x6f, 0xc8, 0x6f, 0x60, 0x8d, 0x6d, 0x88, 0x2a, 0x2f, 0x96, 0xf9, 0x75, 0x6c, + 0x4f, 0x32, 0xd1, 0xd3, 0xf6, 0xe6, 0xaf, 0x35, 0x58, 0x63, 0x26, 0x4e, 0x07, 0x7f, 0x2b, 0x1b, + 0xde, 0x83, 0xc9, 0x7d, 0x97, 0x94, 0x6d, 0x7c, 0x3b, 0xe9, 0x72, 0x4e, 0x5d, 0x3f, 0x20, 0x69, + 0x81, 0xb3, 0xae, 0x7e, 0x18, 0x35, 0x9e, 0x83, 0x1e, 0xee, 0xf8, 0x07, 0xd8, 0x56, 0xa3, 0x0d, + 0x48, 0xc0, 0xd4, 0x1b, 0xa6, 0x80, 0x58, 0x85, 0xb1, 0x7a, 0xc3, 0xe4, 0xef, 0x8a, 0xf4, 0xd0, + 0x6e, 0xfb, 0x9e, 0x49, 0x68, 0xf1, 0x3c, 0x9c, 0xbb, 0x49, 0x1e, 0xfe, 0x33, 0x58, 0x52, 0x06, + 0xe1, 0xfb, 0xbe, 0x0e, 0xe3, 0x75, 0xec, 0x05, 0x7c, 0x18, 0xba, 0xd2, 0x36, 0xf6, 0x02, 0x93, + 0x52, 0xd1, 0xc7, 0x30, 0x55, 0xaf, 0xd2, 0x37, 0x4f, 0x7a, 0xb7, 0x98, 0x65, 0x69, 0xa9, 0x6d, + 0x1d, 0xb7, 0xe9, 0x3b, 0xa8, 0x60, 0x1a, 0x7f, 0xa9, 0x49, 0xe8, 0x44, 0xfd, 0xfa, 0x35, 0x6c, + 0x91, 0x9a, 0x89, 0xd8, 0x4c, 0x5a, 0x02, 0x3d, 0x7c, 0x78, 0xad, 0x46, 0x57, 0x20, 0x89, 0xdc, + 0xb4, 0xb2, 0xfc, 0x0e, 0x8a, 0xea, 0x4c, 0x3e, 0xe8, 0x42, 0xcf, 0xa0, 0xf4, 0x6c, 0xaf, 0x5a, + 0x1d, 0x04, 0xa7, 0xd8, 0x09, 0xec, 0xb6, 0x15, 0xe0, 0xfa, 0xa9, 0xd5, 0xeb, 0x61, 0xa7, 0x4b, + 0x27, 0x78, 0x54, 0xd9, 0x0b, 0x93, 0x3a, 0xab, 0x71, 0x8e, 0x2a, 0x7b, 0xa1, 0x84, 0x49, 0xf8, + 0xe8, 0x3e, 0x8c, 0x37, 0x5f, 0x34, 0x0f, 0x79, 0x39, 0x56, 0xe4, 0x72, 0x84, 0x14, 0x09, 0x52, + 0x09, 0xe3, 0x07, 0x58, 0x89, 0x0d, 0x16, 0xae, 0xe6, 0x63, 0x31, 0x96, 0x46, 0x4b, 0xcd, 0x70, + 0x2c, 0x21, 0xb0, 0x7f, 0x8b, 0x0d, 0xf6, 0x89, 0x32, 0xd8, 0x92, 0x34, 0x98, 0x24, 0x49, 0x45, + 0x78, 0x0b, 0x83, 0xd2, 0x8c, 0xdf, 0xc2, 0xac, 0x3c, 0x71, 0x52, 0xdd, 0x3c, 0xc1, 0x97, 0xfb, + 0x96, 0xd3, 0xe9, 0x61, 0x51, 0xdd, 0x84, 0x04, 0xc2, 0x0d, 0x45, 0x79, 0x79, 0x13, 0x11, 0x50, + 0x11, 0x26, 0xaa, 0xfd, 0xfe, 0xc1, 0x0e, 0x0b, 0x26, 0x93, 0xfd, 0x30, 0x6c, 0x98, 0x91, 0xa6, + 0x7b, 0xcd, 0x00, 0x1b, 0x00, 0xf5, 0x9e, 0x8d, 0x1d, 0x9a, 0x5c, 0xf8, 0x08, 0x12, 0x85, 0x16, + 0x5f, 0x76, 0xd7, 0xb1, 0x82, 0x81, 0xc7, 0x63, 0xd6, 0x8c, 0x08, 0xc6, 0x02, 0xcc, 0x29, 0xd6, + 0x35, 0x0c, 0x98, 0x95, 0x2d, 0x80, 0x10, 0x8c, 0xd7, 0xdd, 0x8e, 0x18, 0x97, 0xfe, 0x6d, 0xfc, + 0x41, 0x83, 0xe2, 0xb3, 0xbd, 0xaa, 0x89, 0xbb, 0x36, 0x6d, 0xdc, 0x86, 0xcb, 0xd9, 0x92, 0x2d, + 0xbf, 0x26, 0x5b, 0x3e, 0x26, 0x29, 0xb6, 0xa0, 0xa2, 0x6c, 0xc1, 0xba, 0xb2, 0x05, 0x49, 0x15, + 0xb6, 0x17, 0x52, 0x1d, 0xfb, 0x7b, 0x0d, 0x96, 0xa4, 0x89, 0x84, 0x93, 0xde, 0x94, 0xe7, 0x51, + 0x4e, 0xce, 0x23, 0xee, 0x09, 0x3f, 0x53, 0xa6, 0xb1, 0x96, 0x32, 0x8d, 0x2b, 0x3d, 0xe2, 0x31, + 0x14, 0xd3, 0x16, 0xa9, 0xee, 0xbd, 0x96, 0xb9, 0xf7, 0x39, 0x79, 0xef, 0x2d, 0x58, 0x4a, 0x99, + 0x28, 0xfa, 0x14, 0x0a, 0x8c, 0xc6, 0xc2, 0x99, 0x3f, 0x96, 0x12, 0xbd, 0x04, 0xfd, 0x3a, 0x8f, + 0x30, 0xfe, 0x59, 0x83, 0xdb, 0xa9, 0x26, 0x46, 0xcb, 0xe4, 0x24, 0x6a, 0x7b, 0x38, 0xe0, 0xd8, + 0xfc, 0x17, 0xa1, 0x1f, 0xf8, 0xfe, 0x80, 0x7f, 0xb2, 0x91, 0x37, 0xf9, 0x2f, 0xf4, 0x47, 0x30, + 0x77, 0x88, 0x3d, 0xdb, 0xed, 0x34, 0x70, 0xdb, 0x75, 0x3a, 0xac, 0x25, 0x33, 0x67, 0xaa, 0x44, + 0x62, 0x86, 0x6a, 0xaf, 0xeb, 0x7a, 0x76, 0x70, 0xca, 0x5e, 0x39, 0xf2, 0x66, 0x44, 0x20, 0xd8, + 0x3b, 0x76, 0xd7, 0x0e, 0xd8, 0x53, 0xe7, 0x9c, 0xc9, 0x7f, 0xa1, 0x12, 0x4c, 0x55, 0xdb, 0x6d, + 0x77, 0xe0, 0x04, 0xf4, 0xbb, 0x85, 0xbc, 0x29, 0x7e, 0x1a, 0x9f, 0x42, 0x31, 0x6d, 0x6b, 0x52, + 0x5d, 0xf5, 0x77, 0x39, 0x58, 0xaa, 0x76, 0x3a, 0xcf, 0xf6, 0xaa, 0x3b, 0x58, 0xbe, 0xb6, 0xfc, + 0x1c, 0xc6, 0x0f, 0x1c, 0x3b, 0xe0, 0x2e, 0xb2, 0xc1, 0x77, 0x3c, 0x45, 0x92, 0x48, 0x91, 0x4d, + 0x27, 0xff, 0x23, 0x13, 0x96, 0x76, 0x7f, 0xb0, 0xfd, 0xc0, 0x76, 0xba, 0xd4, 0xed, 0xd8, 0xc0, + 0xdc, 0x6d, 0x04, 0x48, 0x46, 0x5a, 0xda, 0xbf, 0x65, 0xa6, 0x29, 0xa3, 0x26, 0x2c, 0x3f, 0xc7, + 0xaf, 0x53, 0xbc, 0x38, 0xec, 0x6f, 0x85, 0xb0, 0x29, 0xce, 0x98, 0xa1, 0x2b, 0x07, 0xc9, 0x1f, + 0x72, 0x50, 0x54, 0x17, 0xc6, 0x47, 0x3e, 0x82, 0xa2, 0x34, 0x21, 0xd5, 0x53, 0x67, 0x2a, 0x7a, + 0xfa, 0x72, 0xe4, 0x78, 0x4c, 0x55, 0x47, 0x2f, 0x61, 0x45, 0x9d, 0x94, 0x9a, 0xff, 0xa2, 0xf8, + 0x4a, 0x13, 0xd9, 0xbf, 0x65, 0x66, 0x69, 0xa3, 0x0a, 0x8c, 0x55, 0xdb, 0x67, 0xdc, 0x2c, 0xe9, + 0x5b, 0xc6, 0x56, 0x56, 0x6d, 0x9f, 0x91, 0xc8, 0xae, 0xb6, 0xcf, 0x94, 0x30, 0xfd, 0x3b, 0x0d, + 0x56, 0x32, 0x76, 0x98, 0xc4, 0x0c, 0x23, 0x46, 0xef, 0x9a, 0xa6, 0x44, 0x41, 0xbf, 0x94, 0x1e, + 0x76, 0xe7, 0x2b, 0x9f, 0x5c, 0xed, 0x2f, 0x9b, 0x8c, 0xd2, 0x0c, 0x5f, 0x7e, 0x0d, 0x5d, 0xc0, + 0xd3, 0x77, 0xe0, 0x69, 0x96, 0x6e, 0x0a, 0xb7, 0xd0, 0x14, 0x4d, 0x54, 0x05, 0xcd, 0xa8, 0xc7, + 0xa7, 0x16, 0xae, 0x04, 0xdd, 0x87, 0x49, 0x46, 0xe4, 0x1b, 0x23, 0xbe, 0x4d, 0x89, 0x84, 0x39, + 0xdf, 0xf8, 0x7b, 0x4d, 0x3c, 0xf1, 0x24, 0xfc, 0xfd, 0x4b, 0xc5, 0xdf, 0x3f, 0xe2, 0xf3, 0x4f, + 0x17, 0x56, 0x5c, 0xbe, 0x06, 0x33, 0xef, 0xe2, 0xea, 0xb2, 0x92, 0xec, 0x8c, 0xff, 0xa0, 0x89, + 0xd2, 0x34, 0xe9, 0x8f, 0xbb, 0x30, 0xfb, 0x6e, 0x7e, 0xa8, 0xa8, 0xa1, 0x2f, 0x98, 0x9b, 0xe4, + 0xae, 0x5e, 0xe9, 0x95, 0x9e, 0xf2, 0x8d, 0x78, 0xc5, 0x7a, 0x17, 0x5f, 0x31, 0xd6, 0x53, 0xb4, + 0xc3, 0xe1, 0x8c, 0x65, 0x5a, 0x59, 0x86, 0xac, 0xb0, 0x14, 0xaa, 0xd3, 0x52, 0x5b, 0xa6, 0x87, + 0xa9, 0x7f, 0x8a, 0x93, 0xc2, 0x6f, 0x25, 0xe2, 0x0e, 0x20, 0x04, 0x3e, 0xfd, 0x14, 0xf2, 0xe1, + 0xa7, 0x78, 0xc4, 0xcd, 0x0e, 0x9e, 0x1f, 0x34, 0x99, 0x9b, 0x1d, 0x1e, 0x35, 0x0b, 0x1a, 0x02, + 0x98, 0xdc, 0xd9, 0x7d, 0xba, 0xdb, 0xdc, 0x2d, 0xe4, 0x2a, 0x6f, 0x3e, 0x82, 0x19, 0x62, 0x51, + 0x5e, 0x93, 0xa1, 0x6f, 0x60, 0xbe, 0x81, 0x9d, 0xce, 0x13, 0x8c, 0xfb, 0xd5, 0x9e, 0x7d, 0x81, + 0x7d, 0x24, 0x06, 0x0a, 0x49, 0xe5, 0xe5, 0xc4, 0x03, 0xd8, 0xee, 0x79, 0x3f, 0xb8, 0xbc, 0xaf, + 0xa1, 0x9f, 0xc2, 0x0c, 0xfd, 0xf6, 0x81, 0xbe, 0x35, 0xfb, 0x68, 0x56, 0xfe, 0x1e, 0xa2, 0x2c, + 0x7e, 0x51, 0xe6, 0xe7, 0x1a, 0xb9, 0xdf, 0xb2, 0x82, 0xe8, 0xb9, 0xdb, 0xc1, 0x28, 0x5e, 0x83, + 0x96, 0x13, 0xe3, 0xa2, 0xaf, 0x60, 0x51, 0x3c, 0x9f, 0x85, 0x5f, 0x1a, 0xa0, 0x15, 0x71, 0xb0, + 0xc7, 0xbe, 0x3d, 0x08, 0x87, 0x63, 0x62, 0x5b, 0x30, 0xc5, 0x1b, 0xa4, 0x48, 0x3c, 0xd1, 0xab, + 0xed, 0xd9, 0xb2, 0xfa, 0x91, 0x19, 0xda, 0x86, 0x69, 0xd1, 0x51, 0x45, 0xcb, 0xaa, 0x86, 0x9f, + 0xae, 0xf2, 0xb9, 0x86, 0xf6, 0xc8, 0x0c, 0x83, 0x58, 0x0b, 0xb5, 0x9c, 0xd6, 0x2a, 0x65, 0x5f, + 0x6e, 0x94, 0xc5, 0x5c, 0x62, 0x2a, 0xbb, 0xb0, 0xc4, 0x9f, 0x84, 0x94, 0x2f, 0x9e, 0x32, 0x9a, + 0xae, 0x59, 0x1b, 0x82, 0x1e, 0xc2, 0x12, 0x2f, 0xc3, 0x14, 0x98, 0x42, 0xd8, 0xe0, 0xe0, 0xfd, + 0xb9, 0x4c, 0x80, 0xc7, 0x70, 0xbb, 0x11, 0x5b, 0x0f, 0xeb, 0x82, 0xae, 0xaa, 0x10, 0x52, 0xbb, + 0x35, 0x13, 0xab, 0xc9, 0x5e, 0x1e, 0x29, 0x56, 0xdd, 0xea, 0x5b, 0x27, 0x76, 0xcf, 0x0e, 0x6c, + 0xec, 0xa3, 0xbb, 0xca, 0xaa, 0x64, 0x96, 0xb0, 0xf3, 0x6a, 0xa6, 0x04, 0xfa, 0x16, 0xe6, 0x1e, + 0xe1, 0x20, 0x6a, 0x02, 0xa3, 0x95, 0x44, 0xdb, 0x98, 0x9b, 0x5a, 0xd4, 0x11, 0x6a, 0xe7, 0xf9, + 0x00, 0x0a, 0x47, 0xfd, 0x8e, 0x15, 0x60, 0x09, 0xe2, 0x4e, 0x02, 0x82, 0x8b, 0x58, 0x9e, 0x75, + 0xee, 0x67, 0x2e, 0x70, 0x0b, 0xc6, 0x0f, 0x6d, 0xa7, 0x8b, 0x44, 0xb1, 0x21, 0xb5, 0xef, 0xca, + 0x4b, 0x0a, 0x8d, 0xc7, 0x74, 0x00, 0xfa, 0x35, 0xdd, 0x4f, 0xf4, 0xc7, 0xe1, 0xd7, 0x16, 0x37, + 0xe9, 0x92, 0x96, 0x8d, 0xe8, 0x2b, 0xda, 0x74, 0xc1, 0xd6, 0x36, 0xfa, 0x35, 0xdd, 0x87, 0xa4, + 0x04, 0xba, 0x17, 0x79, 0x79, 0x66, 0xe7, 0xb3, 0xbc, 0x96, 0x39, 0x42, 0x6b, 0x1b, 0x1d, 0x8b, + 0x97, 0xcc, 0x14, 0xf4, 0x8f, 0x95, 0x86, 0xdc, 0x3b, 0x0e, 0xb0, 0x0d, 0xc0, 0xf4, 0x69, 0x20, + 0xab, 0xe1, 0x97, 0xb9, 0x2f, 0xdb, 0x24, 0xcf, 0x74, 0xde, 0x52, 0xe9, 0x5b, 0x92, 0xde, 0x45, + 0xc7, 0x13, 0x95, 0x94, 0x03, 0x44, 0xce, 0x1a, 0x59, 0xfa, 0x07, 0x50, 0xa8, 0xb6, 0xbf, 0x1f, + 0xd8, 0x1e, 0x0e, 0x3b, 0x98, 0x68, 0x23, 0x74, 0x63, 0x95, 0x21, 0xb0, 0x6e, 0xc7, 0x1b, 0xa2, + 0x4f, 0xb1, 0xe5, 0x63, 0xb4, 0x0f, 0x2b, 0x61, 0x0e, 0x8c, 0xb1, 0xd2, 0x35, 0x32, 0x27, 0xb5, + 0x0b, 0xc5, 0xba, 0xe5, 0xb4, 0x71, 0xef, 0xfd, 0x60, 0xbe, 0xa2, 0x31, 0x27, 0x75, 0x77, 0x97, + 0xe3, 0xfa, 0x3c, 0xe4, 0x16, 0xb9, 0xd9, 0x24, 0xd1, 0x2a, 0x2c, 0x30, 0x23, 0x46, 0x66, 0xc9, + 0xd2, 0xce, 0x1a, 0xfe, 0x4b, 0x98, 0xdf, 0x3d, 0xb7, 0x03, 0xda, 0xbb, 0x64, 0x9f, 0xa3, 0xab, + 0xcd, 0xce, 0x4c, 0xc5, 0x7d, 0x58, 0xe4, 0x59, 0x35, 0x6a, 0x7b, 0x86, 0x99, 0x2c, 0xd9, 0x59, + 0x2e, 0x17, 0x05, 0xac, 0xdc, 0x21, 0xbd, 0xaf, 0x7d, 0xae, 0xa1, 0xc7, 0xd4, 0x02, 0x51, 0x6b, + 0x0b, 0xad, 0x45, 0xb1, 0x93, 0x68, 0x78, 0x95, 0xd7, 0xd3, 0x99, 0x3c, 0x0b, 0xd4, 0x60, 0x21, + 0xd6, 0xe0, 0x43, 0x77, 0xc4, 0x99, 0x96, 0xda, 0xf8, 0x4b, 0x39, 0x19, 0xf7, 0x85, 0x55, 0x93, + 0x18, 0xe9, 0xdd, 0xbe, 0x4c, 0x1b, 0x1d, 0x86, 0x47, 0x86, 0xdc, 0xba, 0x43, 0xea, 0x0d, 0x2a, + 0xad, 0xad, 0x97, 0x89, 0xd8, 0x80, 0x42, 0xbc, 0xe9, 0x85, 0x36, 0x42, 0x8b, 0xa4, 0x76, 0xf6, + 0xca, 0x7a, 0x26, 0x9f, 0x1b, 0x4d, 0xda, 0x00, 0xd6, 0xa9, 0x89, 0x6f, 0x80, 0xdc, 0xee, 0x48, + 0x6c, 0x80, 0xda, 0xc5, 0x78, 0x44, 0xbf, 0xd4, 0x92, 0xba, 0x57, 0x28, 0x63, 0x29, 0xe5, 0x3b, + 0x69, 0x38, 0xd1, 0x4e, 0x36, 0xa0, 0x10, 0x6f, 0xe4, 0x84, 0x2b, 0xcd, 0xe8, 0x62, 0x85, 0x2b, + 0xcd, 0xec, 0x00, 0x3d, 0x86, 0x42, 0xbc, 0x8b, 0x13, 0x82, 0x66, 0xb4, 0x77, 0x32, 0xb7, 0x62, + 0x0f, 0x8a, 0xea, 0x06, 0x5e, 0xb3, 0xde, 0xec, 0x6b, 0xc1, 0x9c, 0xd2, 0xbb, 0x41, 0x22, 0x69, + 0xc7, 0xda, 0x44, 0x09, 0xeb, 0xa7, 0xf4, 0x90, 0x98, 0xf5, 0xa5, 0x3e, 0xd0, 0x4d, 0xac, 0x9f, + 0xd6, 0x36, 0x0a, 0x0d, 0x25, 0xcd, 0x4b, 0x64, 0xdc, 0x38, 0xe3, 0x6d, 0x0c, 0x75, 0x93, 0xa9, + 0x65, 0xe1, 0xec, 0xc0, 0x8c, 0xd4, 0x40, 0x42, 0xab, 0x8a, 0x99, 0x14, 0x8f, 0x2f, 0x2b, 0x8b, + 0x53, 0x9d, 0xbd, 0x0e, 0xb3, 0x72, 0x1b, 0x2a, 0x73, 0x16, 0x6b, 0x49, 0x8c, 0xc8, 0x3c, 0x7b, + 0x30, 0x1f, 0x5a, 0x81, 0xcd, 0x66, 0x3d, 0x6e, 0x1c, 0x65, 0x42, 0xd9, 0x4b, 0x42, 0xb2, 0x69, + 0xae, 0x99, 0x52, 0xf6, 0x49, 0xb4, 0xc4, 0xce, 0x64, 0xf5, 0x13, 0xf9, 0x8c, 0x2f, 0xed, 0xaf, + 0xc8, 0x56, 0x0b, 0xb1, 0xbe, 0x19, 0x92, 0xbc, 0x24, 0xa5, 0xd7, 0x54, 0xde, 0xc8, 0x62, 0x73, + 0x33, 0x3d, 0x85, 0xc5, 0x44, 0xdb, 0x0c, 0xe9, 0x4a, 0x3e, 0x4e, 0xf6, 0xbf, 0x32, 0xe7, 0xf7, + 0x54, 0x7c, 0x37, 0x95, 0x86, 0x96, 0xd5, 0x4d, 0xbb, 0xea, 0x06, 0x9d, 0xda, 0x47, 0x0b, 0x6f, + 0x6e, 0x57, 0x75, 0xd9, 0x32, 0x51, 0x7f, 0x0d, 0x28, 0xd9, 0xf5, 0x42, 0x77, 0x23, 0x3b, 0xa5, + 0x37, 0x70, 0xca, 0x1f, 0x5d, 0x21, 0x11, 0x1a, 0xb3, 0x98, 0xd6, 0xf2, 0x42, 0x86, 0x62, 0xcf, + 0xd4, 0x96, 0x55, 0xca, 0x21, 0x67, 0x8a, 0xa0, 0xcc, 0x40, 0xbb, 0xa2, 0x01, 0x96, 0xb9, 0xf8, + 0xdf, 0x88, 0xa6, 0x66, 0xb2, 0x51, 0x15, 0xde, 0x58, 0xaf, 0xe9, 0x64, 0x5d, 0x71, 0xdd, 0x58, + 0x68, 0xd8, 0x5d, 0x47, 0xea, 0x29, 0x85, 0x97, 0x8d, 0x64, 0x33, 0x2b, 0x4c, 0x00, 0x69, 0x2d, + 0xa8, 0x17, 0x50, 0x14, 0x27, 0xa1, 0xdc, 0xb9, 0x41, 0x09, 0x9d, 0xa8, 0xb1, 0x14, 0x26, 0x83, + 0xd4, 0x56, 0xcf, 0x13, 0x98, 0x95, 0x1f, 0x9a, 0x42, 0xa0, 0x94, 0xa7, 0xac, 0x10, 0x28, 0xed, + 0x65, 0x8a, 0x5e, 0x86, 0x9a, 0xe2, 0xf2, 0x11, 0xe1, 0xdd, 0xb9, 0xf2, 0x69, 0xa9, 0xbc, 0x71, + 0xf5, 0x7b, 0x8c, 0x74, 0xc5, 0x8a, 0x5e, 0x42, 0xe4, 0x13, 0x3e, 0xf1, 0x6e, 0x22, 0x9f, 0x31, + 0xc9, 0xc7, 0x93, 0x5a, 0xe1, 0xc7, 0xff, 0xd9, 0xd0, 0x7e, 0x7c, 0xb3, 0xa1, 0xfd, 0xfb, 0x9b, + 0x0d, 0xed, 0xbf, 0xdf, 0x6c, 0x68, 0x27, 0x93, 0x54, 0x7c, 0xfb, 0xff, 0x02, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xb5, 0x56, 0x03, 0x00, 0x3a, 0x00, 0x00, } diff --git a/api/client/proto/authservice.proto b/api/client/proto/authservice.proto index ea805899328..a0711fc19ff 100644 --- a/api/client/proto/authservice.proto +++ b/api/client/proto/authservice.proto @@ -71,6 +71,10 @@ message Event { // DatabaseServer is a resource for database servers. types.DatabaseServerV3 DatabaseServer = 17 [ (gogoproto.jsontag) = "database_server,omitempty" ]; + // WebSession is a regular web session. + types.WebSessionV2 WebSession = 18 [ (gogoproto.jsontag) = "web_session,omitempty" ]; + // WebToken is a web token. + types.WebTokenV3 WebToken = 19 [ (gogoproto.jsontag) = "web_token,omitempty" ]; } } @@ -94,6 +98,8 @@ message WatchKind { // Filter is an optional mapping of custom filter parameters. // Valid values vary by resource kind. map Filter = 4 [ (gogoproto.jsontag) = "filter,omitempty" ]; + // SubKind is a resource subkind to watch + string SubKind = 5 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; } // Set of certificates corresponding to a single public key. @@ -384,6 +390,30 @@ message CreateAppSessionResponse { // DeleteAppSessionRequest contains the parameters used to remove an application web session. message DeleteAppSessionRequest { string SessionID = 1 [ (gogoproto.jsontag) = "session_id" ]; } +// GetWebSessionResponse contains the requested web session. +message GetWebSessionResponse { + // Session is the web session. + types.WebSessionV2 Session = 1 [ (gogoproto.jsontag) = "session" ]; +} + +// GetWebSessionsResponse contains all the requested web sessions. +message GetWebSessionsResponse { + // Sessions is a list of web sessions. + repeated types.WebSessionV2 Sessions = 1 [ (gogoproto.jsontag) = "sessions" ]; +} + +// GetWebTokenResponse contains the requested web token. +message GetWebTokenResponse { + // Token is the web token being requested. + types.WebTokenV3 Token = 1 [ (gogoproto.jsontag) = "token" ]; +} + +// GetWebTokensResponse contains all the requested web tokens. +message GetWebTokensResponse { + // Tokens is a list of web tokens. + repeated types.WebTokenV3 Tokens = 1 [ (gogoproto.jsontag) = "tokens" ]; +} + // GetKubeServicesRequest are the parameters used to request kubernetes services. message GetKubeServicesRequest {} @@ -739,6 +769,24 @@ service AuthService { // DeleteAllAppSessions removes all application web sessions. rpc DeleteAllAppSessions(google.protobuf.Empty) returns (google.protobuf.Empty); + // GetWebSession gets a web session. + rpc GetWebSession(types.GetWebSessionRequest) returns (GetWebSessionResponse); + // GetWebSessions gets all web sessions. + rpc GetWebSessions(google.protobuf.Empty) returns (GetWebSessionsResponse); + // DeleteWebSession deletes a web session. + rpc DeleteWebSession(types.DeleteWebSessionRequest) returns (google.protobuf.Empty); + // DeleteAllWebSessions deletes all web sessions. + rpc DeleteAllWebSessions(google.protobuf.Empty) returns (google.protobuf.Empty); + + // GetWebToken gets a web token. + rpc GetWebToken(types.GetWebTokenRequest) returns (GetWebTokenResponse); + // GetWebTokens gets all web tokens. + rpc GetWebTokens(google.protobuf.Empty) returns (GetWebTokensResponse); + // DeleteWebToken deletes a web token. + rpc DeleteWebToken(types.DeleteWebTokenRequest) returns (google.protobuf.Empty); + // DeleteAllWebTokens deletes all web tokens. + rpc DeleteAllWebTokens(google.protobuf.Empty) returns (google.protobuf.Empty); + // UpdateRemoteCluster updates remote cluster rpc UpdateRemoteCluster(types.RemoteClusterV3) returns (google.protobuf.Empty); diff --git a/api/client/proto/proto.go b/api/client/proto/proto.go new file mode 100644 index 00000000000..dd9320fd9f5 --- /dev/null +++ b/api/client/proto/proto.go @@ -0,0 +1,45 @@ +/* +Copyright 2021 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 proto + +import ( + "github.com/gravitational/teleport/api/types" +) + +// FromWatchKind converts the watch kind value between internal +// and the protobuf format +func FromWatchKind(wk types.WatchKind) WatchKind { + return WatchKind{ + Name: wk.Name, + Kind: wk.Kind, + SubKind: wk.SubKind, + LoadSecrets: wk.LoadSecrets, + Filter: wk.Filter, + } +} + +// ToWatchKind converts the watch kind value between the protobuf +// and the internal format +func ToWatchKind(wk WatchKind) types.WatchKind { + return types.WatchKind{ + Name: wk.Name, + Kind: wk.Kind, + SubKind: wk.SubKind, + LoadSecrets: wk.LoadSecrets, + Filter: wk.Filter, + } +} diff --git a/api/client/sessions.go b/api/client/sessions.go new file mode 100644 index 00000000000..8e4f3280baa --- /dev/null +++ b/api/client/sessions.go @@ -0,0 +1,150 @@ +/* +Copyright 2021 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 client + +import ( + "context" + + "github.com/gravitational/teleport/api/types" + + "github.com/gravitational/trace" + "github.com/gravitational/trace/trail" + + "github.com/golang/protobuf/ptypes/empty" +) + +// GetWebSession returns the web session for the specified request. +// Implements ReadAccessPoint +func (c *Client) GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + return c.WebSessions().Get(ctx, req) +} + +// WebSessions returns the web sessions controller +func (c *Client) WebSessions() types.WebSessionInterface { + return &webSessions{c: c} +} + +// Get returns the web session for the specified request +func (r *webSessions) Get(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + resp, err := r.c.grpc.GetWebSession(ctx, &req) + if err != nil { + return nil, trail.FromGRPC(err) + } + return resp.Session, nil +} + +// List returns the list of all web sessions +func (r *webSessions) List(ctx context.Context) ([]types.WebSession, error) { + resp, err := r.c.grpc.GetWebSessions(ctx, &empty.Empty{}) + if err != nil { + return nil, trail.FromGRPC(err) + } + out := make([]types.WebSession, 0, len(resp.Sessions)) + for _, session := range resp.Sessions { + out = append(out, session) + } + return out, nil +} + +// Upsert not implemented: can only be called locally. +func (r *webSessions) Upsert(ctx context.Context, session types.WebSession) error { + return trace.NotImplemented(notImplementedMessage) +} + +// Delete deletes the web session specified with the request +func (r *webSessions) Delete(ctx context.Context, req types.DeleteWebSessionRequest) error { + _, err := r.c.grpc.DeleteWebSession(ctx, &req) + if err != nil { + return trail.FromGRPC(err) + } + return nil +} + +// DeleteAll deletes all web sessions +func (r *webSessions) DeleteAll(ctx context.Context) error { + _, err := r.c.grpc.DeleteAllWebSessions(ctx, &empty.Empty{}) + if err != nil { + return trail.FromGRPC(err) + } + return nil +} + +type webSessions struct { + c *Client +} + +// GetWebToken returns the web token for the specified request. +// Implements ReadAccessPoint +func (c *Client) GetWebToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + return c.WebTokens().Get(ctx, req) +} + +// WebTokens returns the web tokens controller +func (c *Client) WebTokens() types.WebTokenInterface { + return &webTokens{c: c} +} + +// Get returns the web token for the specified request +func (r *webTokens) Get(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + resp, err := r.c.grpc.GetWebToken(ctx, &req) + if err != nil { + return nil, trail.FromGRPC(err) + } + return resp.Token, nil +} + +// List returns the list of all web tokens +func (r *webTokens) List(ctx context.Context) ([]types.WebToken, error) { + resp, err := r.c.grpc.GetWebTokens(ctx, &empty.Empty{}) + if err != nil { + return nil, trail.FromGRPC(err) + } + out := make([]types.WebToken, 0, len(resp.Tokens)) + for _, token := range resp.Tokens { + out = append(out, token) + } + return out, nil +} + +// Upsert not implemented: can only be called locally. +func (r *webTokens) Upsert(ctx context.Context, token types.WebToken) error { + return trace.NotImplemented(notImplementedMessage) +} + +// Delete deletes the web token specified with the request +func (r *webTokens) Delete(ctx context.Context, req types.DeleteWebTokenRequest) error { + _, err := r.c.grpc.DeleteWebToken(ctx, &req) + if err != nil { + return trail.FromGRPC(err) + } + return nil +} + +// DeleteAll deletes all web tokens +func (r *webTokens) DeleteAll(ctx context.Context) error { + _, err := r.c.grpc.DeleteAllWebTokens(ctx, &empty.Empty{}) + if err != nil { + return trail.FromGRPC(err) + } + return nil +} + +type webTokens struct { + c *Client +} + +const notImplementedMessage = "not implemented: can only be called by auth locally" diff --git a/api/client/streamwatcher.go b/api/client/streamwatcher.go index 7de9f267b36..87644b9c8e2 100644 --- a/api/client/streamwatcher.go +++ b/api/client/streamwatcher.go @@ -31,13 +31,8 @@ import ( func (c *Client) NewWatcher(ctx context.Context, watch types.Watch) (types.Watcher, error) { cancelCtx, cancel := context.WithCancel(ctx) var protoWatch proto.Watch - for _, k := range watch.Kinds { - protoWatch.Kinds = append(protoWatch.Kinds, proto.WatchKind{ - Name: k.Name, - Kind: k.Kind, - LoadSecrets: k.LoadSecrets, - Filter: k.Filter, - }) + for _, kind := range watch.Kinds { + protoWatch.Kinds = append(protoWatch.Kinds, proto.FromWatchKind(kind)) } stream, err := c.grpc.WatchEvents(cancelCtx, &protoWatch) if err != nil { diff --git a/api/defaults/defaults.go b/api/defaults/defaults.go index 5ab7dd82e7b..010898bc0ab 100644 --- a/api/defaults/defaults.go +++ b/api/defaults/defaults.go @@ -40,9 +40,12 @@ const ( // disconnected. The max count mirrors ClientAliveCountMax of sshd. KeepAliveCountMax = 3 - // MaxCertDuration limits maximum duration of validity of issued cert + // MaxCertDuration limits maximum duration of validity of issued certificate MaxCertDuration = 30 * time.Hour + // CertDuration is a default certificate duration. + CertDuration = 12 * time.Hour + // KeepAliveInterval is interval at which Teleport will send keep-alive // messages to the client. The default interval of 5 minutes (300 seconds) is // set to help keep connections alive when using AWS NLBs (which have a default diff --git a/api/types/constants.go b/api/types/constants.go index 78889858d3d..6bb7c3eee54 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -84,6 +84,9 @@ const ( // KindWebSession is a web session resource KindWebSession = "web_session" + // KindWebToken is a web token resource + KindWebToken = "web_token" + // KindAppSession represents an application specific web session. KindAppSession = "app_session" @@ -219,6 +222,9 @@ const ( VerbRotate = "rotate" ) +// WebSessionSubKinds lists subkinds of web session resources +var WebSessionSubKinds = []string{KindAppSession, KindWebSession} + const ( // RecordAtNode is the default. Sessions are recorded at Teleport nodes. RecordAtNode = "node" diff --git a/api/types/events.go b/api/types/events.go index 35815923dd0..fd4a807f8fb 100644 --- a/api/types/events.go +++ b/api/types/events.go @@ -18,10 +18,19 @@ package types import ( "context" + "fmt" "github.com/gravitational/trace" ) +// String returns text description of this event +func (r Event) String() string { + if r.Type == OpDelete { + return fmt.Sprintf("%v(%v/%v)", r.Type, r.Resource.GetKind(), r.Resource.GetSubKind()) + } + return fmt.Sprintf("%v(%v)", r.Type, r.Resource) +} + // Event represents an event that happened in the backend type Event struct { // Type is the event type @@ -87,8 +96,12 @@ type Watch struct { type WatchKind struct { // Kind is a resource kind to watch Kind string + // SubKind optionally specifies the subkind of resource to watch. + // Some resource kinds are ambigious like web sessions, subkind in this case + // specifies the type of web session + SubKind string // Name is an optional specific resource type to watch, - // if specified only the events with a specific resource + // if specified, only the events with the given resource // name will be sent Name string // LoadSecrets specifies whether to load secrets diff --git a/api/types/session.go b/api/types/session.go index 16f7f55d01c..c7dc597e6a3 100644 --- a/api/types/session.go +++ b/api/types/session.go @@ -17,6 +17,7 @@ limitations under the License. package types import ( + "context" "fmt" "time" @@ -25,6 +26,30 @@ import ( "github.com/gravitational/trace" ) +// WebSessionsGetter provides access to web sessions +type WebSessionsGetter interface { + // WebSessions returns the web session manager + WebSessions() WebSessionInterface +} + +// WebSessionInterface defines interface to regular web sessions +type WebSessionInterface interface { + // Get returns a web session state for the given request. + Get(ctx context.Context, req GetWebSessionRequest) (WebSession, error) + + // List gets all regular web sessions. + List(context.Context) ([]WebSession, error) + + // Upsert updates existing or inserts a new web session. + Upsert(ctx context.Context, session WebSession) error + + // Delete deletes the web session described by req. + Delete(ctx context.Context, req DeleteWebSessionRequest) error + + // DeleteAll removes all web sessions. + DeleteAll(context.Context) error +} + // WebSession stores key and value used to authenticate with SSH // notes on behalf of user type WebSession interface { @@ -51,8 +76,6 @@ type WebSession interface { // BearerToken is a special bearer token used for additional // bearer authentication GetBearerToken() string - // SetBearerTokenExpiryTime sets bearer token expiry time - SetBearerTokenExpiryTime(time.Time) // SetExpiryTime sets session expiry time SetExpiryTime(time.Time) // GetBearerTokenExpiryTime - absolute time when token expires @@ -78,6 +101,7 @@ func NewWebSession(name string, kind string, subkind string, spec WebSessionSpec Metadata: Metadata{ Name: name, Namespace: defaults.Namespace, + Expires: &spec.Expires, }, Spec: spec, } @@ -157,13 +181,16 @@ func (ws *WebSessionV2) CheckAndSetDefaults() error { if err != nil { return trace.Wrap(err) } - + if ws.Spec.User == "" { + return trace.BadParameter("missing User") + } return nil } // String returns string representation of the session. func (ws *WebSessionV2) String() string { - return fmt.Sprintf("WebSession(kind=%v,name=%v,id=%v)", ws.GetKind(), ws.GetUser(), ws.GetName()) + return fmt.Sprintf("WebSession(kind=%v/%v,user=%v,id=%v,expires=%v)", + ws.GetKind(), ws.GetSubKind(), ws.GetUser(), ws.GetName(), ws.GetExpiryTime()) } // SetUser sets user associated with this session @@ -210,11 +237,6 @@ func (ws *WebSessionV2) GetBearerToken() string { return ws.Spec.BearerToken } -// SetBearerTokenExpiryTime sets bearer token expiry time -func (ws *WebSessionV2) SetBearerTokenExpiryTime(tm time.Time) { - ws.Spec.BearerTokenExpires = tm -} - // SetExpiryTime sets session expiry time func (ws *WebSessionV2) SetExpiryTime(tm time.Time) { ws.Spec.Expires = tm @@ -281,3 +303,234 @@ func (r CreateAppSessionRequest) Check() error { type DeleteAppSessionRequest struct { SessionID string `json:"session_id"` } + +// NewWebToken returns a new web token with the given expiration and spec +func NewWebToken(expires time.Time, spec WebTokenSpecV3) WebToken { + return &WebTokenV3{ + Kind: KindWebToken, + Version: V3, + Metadata: Metadata{ + Name: spec.Token, + Namespace: defaults.Namespace, + Expires: &expires, + }, + Spec: spec, + } +} + +// WebTokensGetter provides access to web tokens +type WebTokensGetter interface { + // WebTokens returns the tokens manager + WebTokens() WebTokenInterface +} + +// WebTokenInterface defines interface for managing web tokens +type WebTokenInterface interface { + // Get returns a token specified by the request. + Get(ctx context.Context, req GetWebTokenRequest) (WebToken, error) + + // List gets all web tokens. + List(context.Context) ([]WebToken, error) + + // Upsert updates existing or inserts a new web token. + Upsert(ctx context.Context, token WebToken) error + + // Delete deletes the web token described by req. + Delete(ctx context.Context, req DeleteWebTokenRequest) error + + // DeleteAll removes all web tokens. + DeleteAll(context.Context) error +} + +// WebToken is a time-limited unique token bound to a user's session +type WebToken interface { + // Resource represents common properties for all resources. + Resource + + // CheckAndSetDefaults checks and set default values for any missing fields. + CheckAndSetDefaults() error + // GetToken returns the token value + GetToken() string + // SetToken sets the token value + SetToken(token string) + // GetUser returns the user the token is bound to + GetUser() string + // SetUser sets the user the token is bound to + SetUser(user string) + // String returns the text representation of this token + String() string +} + +var _ WebToken = &WebTokenV3{} + +// GetMetadata returns the token metadata +func (r *WebTokenV3) GetMetadata() Metadata { + return r.Metadata +} + +// GetKind returns the token resource kind +func (r *WebTokenV3) GetKind() string { + return r.Kind +} + +// GetSubKind returns the token resource subkind +func (r *WebTokenV3) GetSubKind() string { + return r.SubKind +} + +// SetSubKind sets the token resource subkind +func (r *WebTokenV3) SetSubKind(subKind string) { + r.SubKind = subKind +} + +// GetVersion returns the token resource version +func (r *WebTokenV3) GetVersion() string { + return r.Version +} + +// GetName returns the token value +func (r *WebTokenV3) GetName() string { + return r.Metadata.Name +} + +// SetName sets the token value +func (r *WebTokenV3) SetName(name string) { + r.Metadata.Name = name +} + +// GetResourceID returns the token resource ID +func (r *WebTokenV3) GetResourceID() int64 { + return r.Metadata.GetID() +} + +// SetResourceID sets the token resource ID +func (r *WebTokenV3) SetResourceID(id int64) { + r.Metadata.SetID(id) +} + +// SetTTL sets the token resource TTL (time-to-live) value +func (r *WebTokenV3) SetTTL(clock Clock, ttl time.Duration) { + r.Metadata.SetTTL(clock, ttl) +} + +// GetToken returns the token value +func (r *WebTokenV3) GetToken() string { + return r.Spec.Token +} + +// SetToken sets the token value +func (r *WebTokenV3) SetToken(token string) { + r.Spec.Token = token +} + +// GetUser returns the user this token is bound to +func (r *WebTokenV3) GetUser() string { + return r.Spec.User +} + +// SetUser sets the user this token is bound to +func (r *WebTokenV3) SetUser(user string) { + r.Spec.User = user +} + +// Expiry returns the token absolute expiration time +func (r *WebTokenV3) Expiry() time.Time { + if r.Metadata.Expires == nil { + return time.Time{} + } + return *r.Metadata.Expires +} + +// SetExpiry sets the token absolute expiration time +func (r *WebTokenV3) SetExpiry(t time.Time) { + r.Metadata.Expires = &t +} + +// CheckAndSetDefaults validates this token value and sets defaults +func (r *WebTokenV3) CheckAndSetDefaults() error { + if err := r.Metadata.CheckAndSetDefaults(); err != nil { + return trace.Wrap(err) + } + if r.Spec.User == "" { + return trace.BadParameter("User required") + } + if r.Spec.Token == "" { + return trace.BadParameter("Token required") + } + return nil +} + +// String returns string representation of the token. +func (r *WebTokenV3) String() string { + return fmt.Sprintf("WebToken(kind=%v,user=%v,token=%v,expires=%v)", + r.GetKind(), r.GetUser(), r.GetToken(), r.Expiry()) +} + +// CheckAndSetDefaults validates the request and sets defaults. +func (r *NewWebSessionRequest) CheckAndSetDefaults() error { + if r.User == "" { + return trace.BadParameter("user name required") + } + if len(r.Roles) == 0 { + return trace.BadParameter("roles required") + } + if len(r.Traits) == 0 { + return trace.BadParameter("traits required") + } + if r.SessionTTL == 0 { + r.SessionTTL = defaults.CertDuration + } + return nil +} + +// NewWebSessionRequest defines a request to create a new user +// web session +type NewWebSessionRequest struct { + // User specifies the user this session is bound to + User string + // Roles optionally lists additional user roles + Roles []string + // Traits optionally lists role traits + Traits map[string][]string + // SessionTTL optionally specifies the session time-to-live. + // If left unspecified, the default certificate duration is used. + SessionTTL time.Duration +} + +// Check validates the request. +func (r *GetWebSessionRequest) Check() error { + if r.User == "" { + return trace.BadParameter("user name missing") + } + if r.SessionID == "" { + return trace.BadParameter("session ID missing") + } + return nil +} + +// Check validates the request. +func (r *DeleteWebSessionRequest) Check() error { + if r.SessionID == "" { + return trace.BadParameter("session ID missing") + } + return nil +} + +// Check validates the request. +func (r *GetWebTokenRequest) Check() error { + if r.User == "" { + return trace.BadParameter("user name missing") + } + if r.Token == "" { + return trace.BadParameter("token missing") + } + return nil +} + +// Check validates the request. +func (r *DeleteWebTokenRequest) Check() error { + if r.Token == "" { + return trace.BadParameter("token missing") + } + return nil +} diff --git a/api/types/types.pb.go b/api/types/types.pb.go index 3bb0de4ca2b..4462da17255 100644 --- a/api/types/types.pb.go +++ b/api/types/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_c93fd2eadc8eb1e8, []int{0} + return fileDescriptor_types_104b114ec6253b88, []int{0} } // Type is the type of keep alive, used by servers. At the moment only @@ -95,7 +95,7 @@ func (x KeepAlive_KeepAliveType) String() string { return proto.EnumName(KeepAlive_KeepAliveType_name, int32(x)) } func (KeepAlive_KeepAliveType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{0, 0} + return fileDescriptor_types_104b114ec6253b88, []int{0, 0} } // SigningAlg is the algorithm used for signing new SSH certificates using @@ -126,7 +126,7 @@ func (x CertAuthoritySpecV2_SigningAlgType) String() string { return proto.EnumName(CertAuthoritySpecV2_SigningAlgType_name, int32(x)) } func (CertAuthoritySpecV2_SigningAlgType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{16, 0} + return fileDescriptor_types_104b114ec6253b88, []int{16, 0} } type KeepAlive struct { @@ -150,7 +150,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_c93fd2eadc8eb1e8, []int{0} + return fileDescriptor_types_104b114ec6253b88, []int{0} } func (m *KeepAlive) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -204,7 +204,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_c93fd2eadc8eb1e8, []int{1} + return fileDescriptor_types_104b114ec6253b88, []int{1} } func (m *Metadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -263,7 +263,7 @@ type Rotation struct { func (m *Rotation) Reset() { *m = Rotation{} } func (*Rotation) ProtoMessage() {} func (*Rotation) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{2} + return fileDescriptor_types_104b114ec6253b88, []int{2} } func (m *Rotation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -310,7 +310,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_c93fd2eadc8eb1e8, []int{3} + return fileDescriptor_types_104b114ec6253b88, []int{3} } func (m *RotationSchedule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -359,7 +359,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_c93fd2eadc8eb1e8, []int{4} + return fileDescriptor_types_104b114ec6253b88, []int{4} } func (m *ResourceHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -408,7 +408,7 @@ type DatabaseServerV3 struct { func (m *DatabaseServerV3) Reset() { *m = DatabaseServerV3{} } func (*DatabaseServerV3) ProtoMessage() {} func (*DatabaseServerV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{5} + return fileDescriptor_types_104b114ec6253b88, []int{5} } func (m *DatabaseServerV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -468,7 +468,7 @@ func (m *DatabaseServerSpecV3) Reset() { *m = DatabaseServerSpecV3{} } func (m *DatabaseServerSpecV3) String() string { return proto.CompactTextString(m) } func (*DatabaseServerSpecV3) ProtoMessage() {} func (*DatabaseServerSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{6} + return fileDescriptor_types_104b114ec6253b88, []int{6} } func (m *DatabaseServerSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -510,7 +510,7 @@ func (m *AWS) Reset() { *m = AWS{} } func (m *AWS) String() string { return proto.CompactTextString(m) } func (*AWS) ProtoMessage() {} func (*AWS) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{7} + return fileDescriptor_types_104b114ec6253b88, []int{7} } func (m *AWS) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -559,7 +559,7 @@ type ServerV2 struct { func (m *ServerV2) Reset() { *m = ServerV2{} } func (*ServerV2) ProtoMessage() {} func (*ServerV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{8} + return fileDescriptor_types_104b114ec6253b88, []int{8} } func (m *ServerV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -623,7 +623,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_c93fd2eadc8eb1e8, []int{9} + return fileDescriptor_types_104b114ec6253b88, []int{9} } func (m *ServerSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -678,7 +678,7 @@ func (m *App) Reset() { *m = App{} } func (m *App) String() string { return proto.CompactTextString(m) } func (*App) ProtoMessage() {} func (*App) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{10} + return fileDescriptor_types_104b114ec6253b88, []int{10} } func (m *App) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -721,7 +721,7 @@ func (m *Rewrite) Reset() { *m = Rewrite{} } func (m *Rewrite) String() string { return proto.CompactTextString(m) } func (*Rewrite) ProtoMessage() {} func (*Rewrite) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{11} + return fileDescriptor_types_104b114ec6253b88, []int{11} } func (m *Rewrite) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -768,7 +768,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_c93fd2eadc8eb1e8, []int{12} + return fileDescriptor_types_104b114ec6253b88, []int{12} } func (m *CommandLabelV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -812,7 +812,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_c93fd2eadc8eb1e8, []int{13} + return fileDescriptor_types_104b114ec6253b88, []int{13} } func (m *TLSKeyPair) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -856,7 +856,7 @@ func (m *JWTKeyPair) Reset() { *m = JWTKeyPair{} } func (m *JWTKeyPair) String() string { return proto.CompactTextString(m) } func (*JWTKeyPair) ProtoMessage() {} func (*JWTKeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{14} + return fileDescriptor_types_104b114ec6253b88, []int{14} } func (m *JWTKeyPair) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -905,7 +905,7 @@ type CertAuthorityV2 struct { func (m *CertAuthorityV2) Reset() { *m = CertAuthorityV2{} } func (*CertAuthorityV2) ProtoMessage() {} func (*CertAuthorityV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{15} + return fileDescriptor_types_104b114ec6253b88, []int{15} } func (m *CertAuthorityV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -971,7 +971,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_c93fd2eadc8eb1e8, []int{16} + return fileDescriptor_types_104b114ec6253b88, []int{16} } func (m *CertAuthoritySpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1016,7 +1016,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_c93fd2eadc8eb1e8, []int{17} + return fileDescriptor_types_104b114ec6253b88, []int{17} } func (m *RoleMapping) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1064,7 +1064,7 @@ type ProvisionTokenV1 struct { func (m *ProvisionTokenV1) Reset() { *m = ProvisionTokenV1{} } func (*ProvisionTokenV1) ProtoMessage() {} func (*ProvisionTokenV1) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{18} + return fileDescriptor_types_104b114ec6253b88, []int{18} } func (m *ProvisionTokenV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1113,7 +1113,7 @@ type ProvisionTokenV2 struct { func (m *ProvisionTokenV2) Reset() { *m = ProvisionTokenV2{} } func (*ProvisionTokenV2) ProtoMessage() {} func (*ProvisionTokenV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{19} + return fileDescriptor_types_104b114ec6253b88, []int{19} } func (m *ProvisionTokenV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1157,7 +1157,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_c93fd2eadc8eb1e8, []int{20} + return fileDescriptor_types_104b114ec6253b88, []int{20} } func (m *ProvisionTokenSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1206,7 +1206,7 @@ type StaticTokensV2 struct { func (m *StaticTokensV2) Reset() { *m = StaticTokensV2{} } func (*StaticTokensV2) ProtoMessage() {} func (*StaticTokensV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{21} + return fileDescriptor_types_104b114ec6253b88, []int{21} } func (m *StaticTokensV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1249,7 +1249,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_c93fd2eadc8eb1e8, []int{22} + return fileDescriptor_types_104b114ec6253b88, []int{22} } func (m *StaticTokensSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1298,7 +1298,7 @@ type ClusterNameV2 struct { func (m *ClusterNameV2) Reset() { *m = ClusterNameV2{} } func (*ClusterNameV2) ProtoMessage() {} func (*ClusterNameV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{23} + return fileDescriptor_types_104b114ec6253b88, []int{23} } func (m *ClusterNameV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1341,7 +1341,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_c93fd2eadc8eb1e8, []int{24} + return fileDescriptor_types_104b114ec6253b88, []int{24} } func (m *ClusterNameSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1390,7 +1390,7 @@ type ClusterConfigV3 struct { func (m *ClusterConfigV3) Reset() { *m = ClusterConfigV3{} } func (*ClusterConfigV3) ProtoMessage() {} func (*ClusterConfigV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{25} + return fileDescriptor_types_104b114ec6253b88, []int{25} } func (m *ClusterConfigV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1459,7 +1459,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_c93fd2eadc8eb1e8, []int{26} + return fileDescriptor_types_104b114ec6253b88, []int{26} } func (m *ClusterConfigSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1528,7 +1528,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_c93fd2eadc8eb1e8, []int{27} + return fileDescriptor_types_104b114ec6253b88, []int{27} } func (m *AuditConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1578,7 +1578,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_c93fd2eadc8eb1e8, []int{28} + return fileDescriptor_types_104b114ec6253b88, []int{28} } func (m *Namespace) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1618,7 +1618,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_c93fd2eadc8eb1e8, []int{29} + return fileDescriptor_types_104b114ec6253b88, []int{29} } func (m *NamespaceSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1666,7 +1666,7 @@ type ResetPasswordTokenV3 struct { func (m *ResetPasswordTokenV3) Reset() { *m = ResetPasswordTokenV3{} } func (*ResetPasswordTokenV3) ProtoMessage() {} func (*ResetPasswordTokenV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{30} + return fileDescriptor_types_104b114ec6253b88, []int{30} } func (m *ResetPasswordTokenV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1711,7 +1711,7 @@ func (m *ResetPasswordTokenSpecV3) Reset() { *m = ResetPasswordTokenSpec func (m *ResetPasswordTokenSpecV3) String() string { return proto.CompactTextString(m) } func (*ResetPasswordTokenSpecV3) ProtoMessage() {} func (*ResetPasswordTokenSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{31} + return fileDescriptor_types_104b114ec6253b88, []int{31} } func (m *ResetPasswordTokenSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1759,7 +1759,7 @@ type ResetPasswordTokenSecretsV3 struct { func (m *ResetPasswordTokenSecretsV3) Reset() { *m = ResetPasswordTokenSecretsV3{} } func (*ResetPasswordTokenSecretsV3) ProtoMessage() {} func (*ResetPasswordTokenSecretsV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{32} + return fileDescriptor_types_104b114ec6253b88, []int{32} } func (m *ResetPasswordTokenSecretsV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1804,7 +1804,7 @@ func (m *ResetPasswordTokenSecretsSpecV3) Reset() { *m = ResetPasswordTo func (m *ResetPasswordTokenSecretsSpecV3) String() string { return proto.CompactTextString(m) } func (*ResetPasswordTokenSecretsSpecV3) ProtoMessage() {} func (*ResetPasswordTokenSecretsSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{33} + return fileDescriptor_types_104b114ec6253b88, []int{33} } func (m *ResetPasswordTokenSecretsSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1853,7 +1853,7 @@ type AccessRequestV3 struct { func (m *AccessRequestV3) Reset() { *m = AccessRequestV3{} } func (*AccessRequestV3) ProtoMessage() {} func (*AccessRequestV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{34} + return fileDescriptor_types_104b114ec6253b88, []int{34} } func (m *AccessRequestV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1921,7 +1921,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_c93fd2eadc8eb1e8, []int{35} + return fileDescriptor_types_104b114ec6253b88, []int{35} } func (m *AccessRequestSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1967,7 +1967,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_c93fd2eadc8eb1e8, []int{36} + return fileDescriptor_types_104b114ec6253b88, []int{36} } func (m *AccessRequestFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2011,7 +2011,7 @@ func (m *AccessCapabilities) Reset() { *m = AccessCapabilities{} } func (m *AccessCapabilities) String() string { return proto.CompactTextString(m) } func (*AccessCapabilities) ProtoMessage() {} func (*AccessCapabilities) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{37} + return fileDescriptor_types_104b114ec6253b88, []int{37} } func (m *AccessCapabilities) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2057,7 +2057,7 @@ func (m *AccessCapabilitiesRequest) Reset() { *m = AccessCapabilitiesReq func (m *AccessCapabilitiesRequest) String() string { return proto.CompactTextString(m) } func (*AccessCapabilitiesRequest) ProtoMessage() {} func (*AccessCapabilitiesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{38} + return fileDescriptor_types_104b114ec6253b88, []int{38} } func (m *AccessCapabilitiesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2106,7 +2106,7 @@ type PluginDataV3 struct { func (m *PluginDataV3) Reset() { *m = PluginDataV3{} } func (*PluginDataV3) ProtoMessage() {} func (*PluginDataV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{39} + return fileDescriptor_types_104b114ec6253b88, []int{39} } func (m *PluginDataV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2149,7 +2149,7 @@ func (m *PluginDataEntry) Reset() { *m = PluginDataEntry{} } func (m *PluginDataEntry) String() string { return proto.CompactTextString(m) } func (*PluginDataEntry) ProtoMessage() {} func (*PluginDataEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{40} + return fileDescriptor_types_104b114ec6253b88, []int{40} } func (m *PluginDataEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2191,7 +2191,7 @@ func (m *PluginDataSpecV3) Reset() { *m = PluginDataSpecV3{} } func (m *PluginDataSpecV3) String() string { return proto.CompactTextString(m) } func (*PluginDataSpecV3) ProtoMessage() {} func (*PluginDataSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{41} + return fileDescriptor_types_104b114ec6253b88, []int{41} } func (m *PluginDataSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2238,7 +2238,7 @@ func (m *PluginDataFilter) Reset() { *m = PluginDataFilter{} } func (m *PluginDataFilter) String() string { return proto.CompactTextString(m) } func (*PluginDataFilter) ProtoMessage() {} func (*PluginDataFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{42} + return fileDescriptor_types_104b114ec6253b88, []int{42} } func (m *PluginDataFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2289,7 +2289,7 @@ func (m *PluginDataUpdateParams) Reset() { *m = PluginDataUpdateParams{} func (m *PluginDataUpdateParams) String() string { return proto.CompactTextString(m) } func (*PluginDataUpdateParams) ProtoMessage() {} func (*PluginDataUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{43} + return fileDescriptor_types_104b114ec6253b88, []int{43} } func (m *PluginDataUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2338,7 +2338,7 @@ type RoleV3 struct { func (m *RoleV3) Reset() { *m = RoleV3{} } func (*RoleV3) ProtoMessage() {} func (*RoleV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{44} + return fileDescriptor_types_104b114ec6253b88, []int{44} } func (m *RoleV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2385,7 +2385,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_c93fd2eadc8eb1e8, []int{45} + return fileDescriptor_types_104b114ec6253b88, []int{45} } func (m *RoleSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2458,7 +2458,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_c93fd2eadc8eb1e8, []int{46} + return fileDescriptor_types_104b114ec6253b88, []int{46} } func (m *RoleOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2528,7 +2528,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_c93fd2eadc8eb1e8, []int{47} + return fileDescriptor_types_104b114ec6253b88, []int{47} } func (m *RoleConditions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2581,7 +2581,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_c93fd2eadc8eb1e8, []int{48} + return fileDescriptor_types_104b114ec6253b88, []int{48} } func (m *AccessRequestConditions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2628,7 +2628,7 @@ func (m *AccessRequestClaimMapping) Reset() { *m = AccessRequestClaimMap func (m *AccessRequestClaimMapping) String() string { return proto.CompactTextString(m) } func (*AccessRequestClaimMapping) ProtoMessage() {} func (*AccessRequestClaimMapping) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{49} + return fileDescriptor_types_104b114ec6253b88, []int{49} } func (m *AccessRequestClaimMapping) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2677,7 +2677,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_c93fd2eadc8eb1e8, []int{50} + return fileDescriptor_types_104b114ec6253b88, []int{50} } func (m *Rule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2719,7 +2719,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_c93fd2eadc8eb1e8, []int{51} + return fileDescriptor_types_104b114ec6253b88, []int{51} } func (m *BoolValue) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2768,7 +2768,7 @@ type UserV2 struct { func (m *UserV2) Reset() { *m = UserV2{} } func (*UserV2) ProtoMessage() {} func (*UserV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{52} + return fileDescriptor_types_104b114ec6253b88, []int{52} } func (m *UserV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2832,7 +2832,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_c93fd2eadc8eb1e8, []int{53} + return fileDescriptor_types_104b114ec6253b88, []int{53} } func (m *UserSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2877,7 +2877,7 @@ type ExternalIdentity struct { func (m *ExternalIdentity) Reset() { *m = ExternalIdentity{} } func (*ExternalIdentity) ProtoMessage() {} func (*ExternalIdentity) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{54} + return fileDescriptor_types_104b114ec6253b88, []int{54} } func (m *ExternalIdentity) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2925,7 +2925,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_c93fd2eadc8eb1e8, []int{55} + return fileDescriptor_types_104b114ec6253b88, []int{55} } func (m *LoginStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2970,7 +2970,7 @@ type CreatedBy struct { func (m *CreatedBy) Reset() { *m = CreatedBy{} } func (*CreatedBy) ProtoMessage() {} func (*CreatedBy) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{56} + return fileDescriptor_types_104b114ec6253b88, []int{56} } func (m *CreatedBy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3016,7 +3016,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_c93fd2eadc8eb1e8, []int{57} + return fileDescriptor_types_104b114ec6253b88, []int{57} } func (m *U2FRegistrationData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3063,7 +3063,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_c93fd2eadc8eb1e8, []int{58} + return fileDescriptor_types_104b114ec6253b88, []int{58} } func (m *LocalAuthSecrets) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3117,7 +3117,7 @@ func (m *MFADevice) Reset() { *m = MFADevice{} } func (m *MFADevice) String() string { return proto.CompactTextString(m) } func (*MFADevice) ProtoMessage() {} func (*MFADevice) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{59} + return fileDescriptor_types_104b114ec6253b88, []int{59} } func (m *MFADevice) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3269,7 +3269,7 @@ func (m *TOTPDevice) Reset() { *m = TOTPDevice{} } func (m *TOTPDevice) String() string { return proto.CompactTextString(m) } func (*TOTPDevice) ProtoMessage() {} func (*TOTPDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{60} + return fileDescriptor_types_104b114ec6253b88, []int{60} } func (m *TOTPDevice) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3315,7 +3315,7 @@ func (m *U2FDevice) Reset() { *m = U2FDevice{} } func (m *U2FDevice) String() string { return proto.CompactTextString(m) } func (*U2FDevice) ProtoMessage() {} func (*U2FDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{61} + return fileDescriptor_types_104b114ec6253b88, []int{61} } func (m *U2FDevice) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3361,7 +3361,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_c93fd2eadc8eb1e8, []int{62} + return fileDescriptor_types_104b114ec6253b88, []int{62} } func (m *ConnectorRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3403,7 +3403,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_c93fd2eadc8eb1e8, []int{63} + return fileDescriptor_types_104b114ec6253b88, []int{63} } func (m *UserRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3453,7 +3453,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_c93fd2eadc8eb1e8, []int{64} + return fileDescriptor_types_104b114ec6253b88, []int{64} } func (m *ReverseTunnelV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3500,7 +3500,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_c93fd2eadc8eb1e8, []int{65} + return fileDescriptor_types_104b114ec6253b88, []int{65} } func (m *ReverseTunnelSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3549,7 +3549,7 @@ type TunnelConnectionV2 struct { func (m *TunnelConnectionV2) Reset() { *m = TunnelConnectionV2{} } func (*TunnelConnectionV2) ProtoMessage() {} func (*TunnelConnectionV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{66} + return fileDescriptor_types_104b114ec6253b88, []int{66} } func (m *TunnelConnectionV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3597,7 +3597,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_c93fd2eadc8eb1e8, []int{67} + return fileDescriptor_types_104b114ec6253b88, []int{67} } func (m *TunnelConnectionSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3645,7 +3645,7 @@ func (m *SemaphoreFilter) Reset() { *m = SemaphoreFilter{} } func (m *SemaphoreFilter) String() string { return proto.CompactTextString(m) } func (*SemaphoreFilter) ProtoMessage() {} func (*SemaphoreFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{68} + return fileDescriptor_types_104b114ec6253b88, []int{68} } func (m *SemaphoreFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3696,7 +3696,7 @@ func (m *AcquireSemaphoreRequest) Reset() { *m = AcquireSemaphoreRequest func (m *AcquireSemaphoreRequest) String() string { return proto.CompactTextString(m) } func (*AcquireSemaphoreRequest) ProtoMessage() {} func (*AcquireSemaphoreRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{69} + return fileDescriptor_types_104b114ec6253b88, []int{69} } func (m *AcquireSemaphoreRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3744,7 +3744,7 @@ func (m *SemaphoreLease) Reset() { *m = SemaphoreLease{} } func (m *SemaphoreLease) String() string { return proto.CompactTextString(m) } func (*SemaphoreLease) ProtoMessage() {} func (*SemaphoreLease) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{70} + return fileDescriptor_types_104b114ec6253b88, []int{70} } func (m *SemaphoreLease) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3790,7 +3790,7 @@ func (m *SemaphoreLeaseRef) Reset() { *m = SemaphoreLeaseRef{} } func (m *SemaphoreLeaseRef) String() string { return proto.CompactTextString(m) } func (*SemaphoreLeaseRef) ProtoMessage() {} func (*SemaphoreLeaseRef) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{71} + return fileDescriptor_types_104b114ec6253b88, []int{71} } func (m *SemaphoreLeaseRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3839,7 +3839,7 @@ type SemaphoreV3 struct { func (m *SemaphoreV3) Reset() { *m = SemaphoreV3{} } func (*SemaphoreV3) ProtoMessage() {} func (*SemaphoreV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{72} + return fileDescriptor_types_104b114ec6253b88, []int{72} } func (m *SemaphoreV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3881,7 +3881,7 @@ func (m *SemaphoreSpecV3) Reset() { *m = SemaphoreSpecV3{} } func (m *SemaphoreSpecV3) String() string { return proto.CompactTextString(m) } func (*SemaphoreSpecV3) ProtoMessage() {} func (*SemaphoreSpecV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{73} + return fileDescriptor_types_104b114ec6253b88, []int{73} } func (m *SemaphoreSpecV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3930,7 +3930,7 @@ type WebSessionV2 struct { func (m *WebSessionV2) Reset() { *m = WebSessionV2{} } func (*WebSessionV2) ProtoMessage() {} func (*WebSessionV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{74} + return fileDescriptor_types_104b114ec6253b88, []int{74} } func (m *WebSessionV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3987,7 +3987,7 @@ func (m *WebSessionSpecV2) Reset() { *m = WebSessionSpecV2{} } func (m *WebSessionSpecV2) String() string { return proto.CompactTextString(m) } func (*WebSessionSpecV2) ProtoMessage() {} func (*WebSessionSpecV2) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{75} + return fileDescriptor_types_104b114ec6253b88, []int{75} } func (m *WebSessionSpecV2) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4036,7 +4036,7 @@ type RemoteClusterV3 struct { func (m *RemoteClusterV3) Reset() { *m = RemoteClusterV3{} } func (*RemoteClusterV3) ProtoMessage() {} func (*RemoteClusterV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{76} + return fileDescriptor_types_104b114ec6253b88, []int{76} } func (m *RemoteClusterV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4080,7 +4080,7 @@ func (m *RemoteClusterStatusV3) Reset() { *m = RemoteClusterStatusV3{} } func (m *RemoteClusterStatusV3) String() string { return proto.CompactTextString(m) } func (*RemoteClusterStatusV3) ProtoMessage() {} func (*RemoteClusterStatusV3) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{77} + return fileDescriptor_types_104b114ec6253b88, []int{77} } func (m *RemoteClusterStatusV3) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4128,7 +4128,7 @@ func (m *KubernetesCluster) Reset() { *m = KubernetesCluster{} } func (m *KubernetesCluster) String() string { return proto.CompactTextString(m) } func (*KubernetesCluster) ProtoMessage() {} func (*KubernetesCluster) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c93fd2eadc8eb1e8, []int{78} + return fileDescriptor_types_104b114ec6253b88, []int{78} } func (m *KubernetesCluster) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4157,6 +4157,278 @@ func (m *KubernetesCluster) XXX_DiscardUnknown() { var xxx_messageInfo_KubernetesCluster proto.InternalMessageInfo +// WebTokenV3 describes a web token. Web tokens are used as a transport to relay bearer tokens +// to the client. +// Initially bound to a web session, these have been factored out into a separate resource to +// enable separate lifecycle management. +type WebTokenV3 struct { + // Kind is a resource kind + Kind string `protobuf:"bytes,1,opt,name=Kind,proto3" json:"kind"` + // SubKind is an optional resource sub kind + SubKind string `protobuf:"bytes,2,opt,name=SubKind,proto3" json:"sub_kind,omitempty"` + // Version is the resource version + Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"version"` + // Metadata is resource metadata + Metadata Metadata `protobuf:"bytes,4,opt,name=Metadata" json:"metadata"` + // Spec defines the web token + Spec WebTokenSpecV3 `protobuf:"bytes,5,opt,name=Spec" json:"spec"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WebTokenV3) Reset() { *m = WebTokenV3{} } +func (*WebTokenV3) ProtoMessage() {} +func (*WebTokenV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{79} +} +func (m *WebTokenV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WebTokenV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WebTokenV3.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 *WebTokenV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_WebTokenV3.Merge(dst, src) +} +func (m *WebTokenV3) XXX_Size() int { + return m.Size() +} +func (m *WebTokenV3) XXX_DiscardUnknown() { + xxx_messageInfo_WebTokenV3.DiscardUnknown(m) +} + +var xxx_messageInfo_WebTokenV3 proto.InternalMessageInfo + +// WebTokenSpecV3 is a unique time-limited token bound to a user's web session +type WebTokenSpecV3 struct { + // User specifies the user the token is bound to. + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // Token specifies the token's value. + Token string `protobuf:"bytes,2,opt,name=Token,proto3" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WebTokenSpecV3) Reset() { *m = WebTokenSpecV3{} } +func (m *WebTokenSpecV3) String() string { return proto.CompactTextString(m) } +func (*WebTokenSpecV3) ProtoMessage() {} +func (*WebTokenSpecV3) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{80} +} +func (m *WebTokenSpecV3) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WebTokenSpecV3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WebTokenSpecV3.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 *WebTokenSpecV3) XXX_Merge(src proto.Message) { + xxx_messageInfo_WebTokenSpecV3.Merge(dst, src) +} +func (m *WebTokenSpecV3) XXX_Size() int { + return m.Size() +} +func (m *WebTokenSpecV3) XXX_DiscardUnknown() { + xxx_messageInfo_WebTokenSpecV3.DiscardUnknown(m) +} + +var xxx_messageInfo_WebTokenSpecV3 proto.InternalMessageInfo + +// GetWebSessionRequest describes a request to query a web session +type GetWebSessionRequest struct { + // User specifies the user the web session is for. + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // SessionID specifies the web session ID. + SessionID string `protobuf:"bytes,2,opt,name=SessionID,proto3" json:"session_id"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebSessionRequest) Reset() { *m = GetWebSessionRequest{} } +func (m *GetWebSessionRequest) String() string { return proto.CompactTextString(m) } +func (*GetWebSessionRequest) ProtoMessage() {} +func (*GetWebSessionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{81} +} +func (m *GetWebSessionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebSessionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebSessionRequest.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 *GetWebSessionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebSessionRequest.Merge(dst, src) +} +func (m *GetWebSessionRequest) XXX_Size() int { + return m.Size() +} +func (m *GetWebSessionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebSessionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebSessionRequest proto.InternalMessageInfo + +// DeleteWebSessionRequest describes a request to delete a web session +type DeleteWebSessionRequest struct { + // User specifies the user the session is bound to + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // SessionID specifies the web session ID to delete. + SessionID string `protobuf:"bytes,2,opt,name=SessionID,proto3" json:"session_id"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteWebSessionRequest) Reset() { *m = DeleteWebSessionRequest{} } +func (m *DeleteWebSessionRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteWebSessionRequest) ProtoMessage() {} +func (*DeleteWebSessionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{82} +} +func (m *DeleteWebSessionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteWebSessionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteWebSessionRequest.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 *DeleteWebSessionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteWebSessionRequest.Merge(dst, src) +} +func (m *DeleteWebSessionRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteWebSessionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteWebSessionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteWebSessionRequest proto.InternalMessageInfo + +// GetWebTokenRequest describes a request to query a web token +type GetWebTokenRequest struct { + // User specifies the user the token is for. + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // Token specifies the token to get. + Token string `protobuf:"bytes,2,opt,name=Token,proto3" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetWebTokenRequest) Reset() { *m = GetWebTokenRequest{} } +func (m *GetWebTokenRequest) String() string { return proto.CompactTextString(m) } +func (*GetWebTokenRequest) ProtoMessage() {} +func (*GetWebTokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{83} +} +func (m *GetWebTokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetWebTokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetWebTokenRequest.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 *GetWebTokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetWebTokenRequest.Merge(dst, src) +} +func (m *GetWebTokenRequest) XXX_Size() int { + return m.Size() +} +func (m *GetWebTokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetWebTokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetWebTokenRequest proto.InternalMessageInfo + +// DeleteWebTokenRequest describes a request to delete a web token +type DeleteWebTokenRequest struct { + // User specifies the user the token is for. + User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"` + // Token specifies the token to delete. + Token string `protobuf:"bytes,2,opt,name=Token,proto3" json:"token"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteWebTokenRequest) Reset() { *m = DeleteWebTokenRequest{} } +func (m *DeleteWebTokenRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteWebTokenRequest) ProtoMessage() {} +func (*DeleteWebTokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_types_104b114ec6253b88, []int{84} +} +func (m *DeleteWebTokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteWebTokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteWebTokenRequest.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 *DeleteWebTokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteWebTokenRequest.Merge(dst, src) +} +func (m *DeleteWebTokenRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteWebTokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteWebTokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteWebTokenRequest proto.InternalMessageInfo + func init() { proto.RegisterType((*KeepAlive)(nil), "types.KeepAlive") proto.RegisterType((*Metadata)(nil), "types.Metadata") @@ -4248,6 +4520,12 @@ func init() { proto.RegisterType((*KubernetesCluster)(nil), "types.KubernetesCluster") proto.RegisterMapType((map[string]CommandLabelV2)(nil), "types.KubernetesCluster.DynamicLabelsEntry") proto.RegisterMapType((map[string]string)(nil), "types.KubernetesCluster.StaticLabelsEntry") + proto.RegisterType((*WebTokenV3)(nil), "types.WebTokenV3") + proto.RegisterType((*WebTokenSpecV3)(nil), "types.WebTokenSpecV3") + proto.RegisterType((*GetWebSessionRequest)(nil), "types.GetWebSessionRequest") + proto.RegisterType((*DeleteWebSessionRequest)(nil), "types.DeleteWebSessionRequest") + proto.RegisterType((*GetWebTokenRequest)(nil), "types.GetWebTokenRequest") + proto.RegisterType((*DeleteWebTokenRequest)(nil), "types.DeleteWebTokenRequest") proto.RegisterEnum("types.RequestState", RequestState_name, RequestState_value) proto.RegisterEnum("types.KeepAlive_KeepAliveType", KeepAlive_KeepAliveType_name, KeepAlive_KeepAliveType_value) proto.RegisterEnum("types.CertAuthoritySpecV2_SigningAlgType", CertAuthoritySpecV2_SigningAlgType_name, CertAuthoritySpecV2_SigningAlgType_value) @@ -8679,6 +8957,226 @@ func (m *KubernetesCluster) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *WebTokenV3) 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 *WebTokenV3) 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())) + n102, err := m.Metadata.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n102 + dAtA[i] = 0x2a + i++ + i = encodeVarintTypes(dAtA, i, uint64(m.Spec.Size())) + n103, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n103 + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *WebTokenSpecV3) 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 *WebTokenSpecV3) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if len(m.Token) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Token))) + i += copy(dAtA[i:], m.Token) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *GetWebSessionRequest) 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 *GetWebSessionRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if len(m.SessionID) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.SessionID))) + i += copy(dAtA[i:], m.SessionID) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *DeleteWebSessionRequest) 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 *DeleteWebSessionRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if len(m.SessionID) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.SessionID))) + i += copy(dAtA[i:], m.SessionID) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *GetWebTokenRequest) 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 *GetWebTokenRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if len(m.Token) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Token))) + i += copy(dAtA[i:], m.Token) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *DeleteWebTokenRequest) 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 *DeleteWebTokenRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.User) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.User))) + i += copy(dAtA[i:], m.User) + } + if len(m.Token) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintTypes(dAtA, i, uint64(len(m.Token))) + i += copy(dAtA[i:], m.Token) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -10712,6 +11210,116 @@ func (m *KubernetesCluster) Size() (n int) { return n } +func (m *WebTokenV3) 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 *WebTokenSpecV3) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetWebSessionRequest) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.SessionID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *DeleteWebSessionRequest) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.SessionID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetWebTokenRequest) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *DeleteWebTokenRequest) Size() (n int) { + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovTypes(x uint64) (n int) { for { n++ @@ -25566,6 +26174,749 @@ func (m *KubernetesCluster) Unmarshal(dAtA []byte) error { } return nil } +func (m *WebTokenV3) 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: WebTokenV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WebTokenV3: 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 *WebTokenSpecV3) 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: WebTokenSpecV3: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WebTokenSpecV3: 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 Token", 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.Token = string(dAtA[iNdEx:postIndex]) + 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 *GetWebSessionRequest) 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: GetWebSessionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebSessionRequest: 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 SessionID", 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.SessionID = string(dAtA[iNdEx:postIndex]) + 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 *DeleteWebSessionRequest) 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: DeleteWebSessionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteWebSessionRequest: 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 SessionID", 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.SessionID = string(dAtA[iNdEx:postIndex]) + 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 *GetWebTokenRequest) 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: GetWebTokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetWebTokenRequest: 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 Token", 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.Token = string(dAtA[iNdEx:postIndex]) + 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 *DeleteWebTokenRequest) 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: DeleteWebTokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteWebTokenRequest: 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 Token", 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.Token = string(dAtA[iNdEx:postIndex]) + 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 skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 @@ -25671,390 +27022,395 @@ var ( ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("types.proto", fileDescriptor_types_c93fd2eadc8eb1e8) } +func init() { proto.RegisterFile("types.proto", fileDescriptor_types_104b114ec6253b88) } -var fileDescriptor_types_c93fd2eadc8eb1e8 = []byte{ - // 6099 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x3c, 0x5b, 0x8c, 0x1b, 0xc9, - 0x71, 0x1a, 0x92, 0xbb, 0x24, 0x6b, 0x1f, 0xa2, 0x7a, 0xf5, 0xa0, 0xf6, 0x74, 0xa2, 0x3c, 0xb2, - 0x75, 0xd2, 0x59, 0xb7, 0x6b, 0xed, 0xf9, 0xce, 0xbe, 0xb3, 0x2e, 0x32, 0xb9, 0xbb, 0xd2, 0xae, - 0x57, 0x8f, 0xf5, 0x70, 0x25, 0xc5, 0xf1, 0x63, 0x32, 0xe4, 0xb4, 0xb8, 0x93, 0x25, 0x39, 0x73, - 0x33, 0xc3, 0x95, 0xf6, 0x2b, 0x71, 0x80, 0xc4, 0x08, 0x8c, 0xf8, 0x85, 0x18, 0x8e, 0x81, 0x04, - 0x09, 0x0c, 0x04, 0x31, 0x12, 0xf8, 0x2b, 0x1f, 0xf9, 0xca, 0x47, 0x00, 0x03, 0x39, 0xe4, 0x2b, - 0x7f, 0x41, 0x8c, 0x84, 0x49, 0x9c, 0x7c, 0xd1, 0xbf, 0xf9, 0xc9, 0x21, 0x01, 0x82, 0xae, 0xee, - 0x9e, 0xe9, 0x19, 0x92, 0xbb, 0xd4, 0x59, 0x07, 0x64, 0xef, 0x6b, 0x97, 0xd5, 0x55, 0xd5, 0xdd, - 0xd5, 0x55, 0xd5, 0x55, 0xd5, 0xdd, 0x03, 0x33, 0xe1, 0x81, 0x47, 0x83, 0x25, 0xcf, 0x77, 0x43, - 0x97, 0x4c, 0xe1, 0x8f, 0xc5, 0xd3, 0x2d, 0xb7, 0xe5, 0x22, 0x64, 0x99, 0xfd, 0xc7, 0x1b, 0x17, - 0x2b, 0x2d, 0xd7, 0x6d, 0xb5, 0xe9, 0x32, 0xfe, 0x6a, 0xf4, 0x9e, 0x2c, 0x87, 0x4e, 0x87, 0x06, - 0xa1, 0xd5, 0xf1, 0x04, 0xc2, 0x6a, 0xcb, 0x09, 0x77, 0x7b, 0x8d, 0xa5, 0xa6, 0xdb, 0x59, 0x6e, - 0xf9, 0xd6, 0xbe, 0x13, 0x5a, 0xa1, 0xe3, 0x76, 0xad, 0xf6, 0x72, 0x48, 0xdb, 0xd4, 0x73, 0xfd, - 0x70, 0xd9, 0xf2, 0x9c, 0x65, 0xec, 0x63, 0xf9, 0xa9, 0x6f, 0x79, 0x1e, 0xf5, 0xe3, 0x7f, 0x38, - 0x13, 0xfd, 0x7f, 0x32, 0x50, 0xdc, 0xa2, 0xd4, 0xab, 0xb6, 0x9d, 0x7d, 0x4a, 0x2e, 0x43, 0xee, - 0xbe, 0xd5, 0xa1, 0x65, 0xed, 0x92, 0x76, 0xb5, 0x58, 0x3b, 0x39, 0xe8, 0x57, 0x66, 0x02, 0xea, - 0xef, 0x53, 0xdf, 0xec, 0x5a, 0x1d, 0x6a, 0x60, 0x23, 0xf9, 0x24, 0x14, 0xd9, 0xdf, 0xc0, 0xb3, - 0x9a, 0xb4, 0x9c, 0x41, 0xcc, 0xb9, 0x41, 0xbf, 0x52, 0xec, 0x4a, 0xa0, 0x11, 0xb7, 0x93, 0x2b, - 0x90, 0xbf, 0x4b, 0xad, 0x80, 0x6e, 0xae, 0x95, 0xb3, 0x97, 0xb4, 0xab, 0xd9, 0xda, 0xec, 0xa0, - 0x5f, 0x29, 0xb4, 0x19, 0xc8, 0x74, 0x6c, 0x43, 0x36, 0x92, 0x4d, 0xc8, 0xaf, 0x3f, 0xf3, 0x1c, - 0x9f, 0x06, 0xe5, 0xdc, 0x25, 0xed, 0xea, 0xcc, 0xca, 0xe2, 0x12, 0x9f, 0xff, 0x92, 0x9c, 0xff, - 0xd2, 0x8e, 0x9c, 0x7f, 0x6d, 0xe1, 0xbd, 0x7e, 0xe5, 0xc4, 0xa0, 0x5f, 0xc9, 0x53, 0x4e, 0xf2, - 0x9d, 0x7f, 0xad, 0x68, 0x86, 0xa4, 0x27, 0x37, 0x21, 0xb7, 0x73, 0xe0, 0xd1, 0x72, 0xf1, 0x92, - 0x76, 0x75, 0x7e, 0xe5, 0xe2, 0x12, 0x97, 0x78, 0x34, 0xc9, 0xf8, 0x3f, 0x86, 0x55, 0x2b, 0x0c, - 0xfa, 0x95, 0x1c, 0x43, 0x31, 0x90, 0x8a, 0xbc, 0x06, 0xd3, 0x1b, 0x6e, 0x10, 0x6e, 0xae, 0x95, - 0x01, 0xa7, 0x76, 0x66, 0xd0, 0xaf, 0x9c, 0xda, 0x75, 0x83, 0xd0, 0x74, 0xec, 0xeb, 0x6e, 0xc7, - 0x09, 0x69, 0xc7, 0x0b, 0x0f, 0x0c, 0x81, 0xa4, 0xbf, 0x03, 0x73, 0x09, 0x7e, 0x64, 0x06, 0xf2, - 0x0f, 0xef, 0x6f, 0xdd, 0x7f, 0xf0, 0xf8, 0x7e, 0xe9, 0x04, 0x29, 0x40, 0xee, 0xfe, 0x83, 0xb5, - 0xf5, 0x92, 0x46, 0xf2, 0x90, 0xad, 0x6e, 0x6f, 0x97, 0x32, 0x64, 0x16, 0x0a, 0x6b, 0xd5, 0x9d, - 0x6a, 0xad, 0x5a, 0x5f, 0x2f, 0x65, 0xf5, 0x6f, 0x64, 0xa1, 0x70, 0x8f, 0x86, 0x96, 0x6d, 0x85, - 0x16, 0xb9, 0x90, 0x90, 0x3e, 0x0e, 0x4c, 0x11, 0xfb, 0xe5, 0x61, 0xb1, 0x4f, 0x0d, 0xfa, 0x15, - 0xed, 0x35, 0x55, 0xdc, 0x9f, 0x83, 0x99, 0x35, 0x1a, 0x34, 0x7d, 0xc7, 0x63, 0xaa, 0x80, 0x22, - 0x2f, 0xd6, 0xce, 0x0f, 0xfa, 0x95, 0x33, 0x76, 0x0c, 0x56, 0xa6, 0xa1, 0x62, 0x93, 0x4d, 0x98, - 0xbe, 0x6b, 0x35, 0x68, 0x3b, 0x28, 0x4f, 0x5d, 0xca, 0x5e, 0x9d, 0x59, 0x79, 0x49, 0x88, 0x4e, - 0x0e, 0x70, 0x89, 0xb7, 0xae, 0x77, 0x43, 0xff, 0xa0, 0x76, 0x7a, 0xd0, 0xaf, 0x94, 0xda, 0x08, - 0x50, 0xc5, 0xc2, 0x51, 0x48, 0x3d, 0x5e, 0xce, 0xe9, 0x23, 0x97, 0xf3, 0xe5, 0xf7, 0xfa, 0x15, - 0x8d, 0x89, 0x59, 0x2c, 0x67, 0xcc, 0x2f, 0xb9, 0xb0, 0x97, 0x20, 0xb3, 0xb9, 0x56, 0xce, 0xa3, - 0x1a, 0x95, 0x06, 0xfd, 0xca, 0x6c, 0x62, 0x45, 0x32, 0x9b, 0x6b, 0x8b, 0x6f, 0xc1, 0x8c, 0x32, - 0x46, 0x52, 0x82, 0xec, 0x1e, 0x3d, 0xe0, 0xf2, 0x34, 0xd8, 0xbf, 0xe4, 0x34, 0x4c, 0xed, 0x5b, - 0xed, 0x9e, 0x10, 0xa0, 0xc1, 0x7f, 0xbc, 0x9d, 0xf9, 0xac, 0xa6, 0x7f, 0x2f, 0x07, 0x05, 0xc3, - 0xe5, 0x26, 0x44, 0xae, 0xc1, 0x54, 0x3d, 0xb4, 0x42, 0xb9, 0x14, 0x0b, 0x83, 0x7e, 0xe5, 0x64, - 0xc0, 0x00, 0x4a, 0x7f, 0x1c, 0x83, 0xa1, 0x6e, 0xef, 0x5a, 0x81, 0x5c, 0x12, 0x44, 0xf5, 0x18, - 0x40, 0x45, 0x45, 0x0c, 0x72, 0x05, 0x72, 0xf7, 0x5c, 0x9b, 0x8a, 0x55, 0x21, 0x83, 0x7e, 0x65, - 0xbe, 0xe3, 0xda, 0x2a, 0x22, 0xb6, 0x93, 0xeb, 0x50, 0x5c, 0xed, 0xf9, 0x3e, 0xed, 0x32, 0x2d, - 0xcc, 0x21, 0xf2, 0xfc, 0xa0, 0x5f, 0x81, 0x26, 0x07, 0x32, 0xbb, 0x89, 0x11, 0x98, 0xa8, 0xeb, - 0xa1, 0xe5, 0x87, 0xd4, 0x2e, 0x4f, 0x4d, 0x24, 0x6a, 0x66, 0x39, 0xa7, 0x02, 0x4e, 0x92, 0x16, - 0xb5, 0xe0, 0x44, 0x36, 0x60, 0xe6, 0x8e, 0x6f, 0x35, 0xe9, 0x36, 0xf5, 0x1d, 0xd7, 0xc6, 0x35, - 0xcc, 0xd6, 0xae, 0x0c, 0xfa, 0x95, 0xb3, 0x2d, 0x06, 0x36, 0x3d, 0x84, 0xc7, 0xd4, 0xef, 0xf7, - 0x2b, 0x85, 0xb5, 0x9e, 0x8f, 0xd2, 0x33, 0x54, 0x52, 0xf2, 0xeb, 0x6c, 0x49, 0x82, 0x10, 0x45, - 0x4b, 0x6d, 0x5c, 0xbd, 0xc3, 0x87, 0xa8, 0x8b, 0x21, 0x9e, 0x6d, 0x5b, 0x41, 0x68, 0xfa, 0x9c, - 0x2e, 0x35, 0x4e, 0x95, 0x25, 0x79, 0x00, 0x85, 0x7a, 0x73, 0x97, 0xda, 0xbd, 0x36, 0x2d, 0x17, - 0x90, 0xfd, 0x39, 0xa1, 0xb8, 0x72, 0x3d, 0x65, 0x73, 0x6d, 0x51, 0xf0, 0x26, 0x81, 0x80, 0x28, - 0xb2, 0x8f, 0x98, 0xbc, 0x5d, 0xf8, 0xc3, 0x3f, 0xad, 0x9c, 0xf8, 0xad, 0x7f, 0xbe, 0x74, 0x42, - 0xff, 0xeb, 0x0c, 0x94, 0xd2, 0x4c, 0xc8, 0x13, 0x98, 0x7b, 0xe8, 0xd9, 0x56, 0x48, 0x57, 0xdb, - 0x0e, 0xed, 0x86, 0x01, 0x2a, 0xc9, 0xe1, 0x73, 0xfa, 0xb8, 0xe8, 0xb7, 0xdc, 0x43, 0x42, 0xb3, - 0xc9, 0x29, 0x53, 0xb3, 0x4a, 0xb2, 0x8d, 0xfb, 0xa9, 0xa3, 0x0b, 0x0e, 0x50, 0xc3, 0x9e, 0xaf, - 0x1f, 0xee, 0xbc, 0xc7, 0xf4, 0x23, 0xd8, 0x0a, 0x05, 0xea, 0xda, 0x8d, 0x03, 0xd4, 0xcc, 0xc9, - 0x15, 0x88, 0x91, 0x8c, 0x50, 0x20, 0x06, 0xd6, 0xff, 0x53, 0x83, 0x79, 0x83, 0x06, 0x6e, 0xcf, - 0x6f, 0xd2, 0x0d, 0x6a, 0xd9, 0xd4, 0x67, 0xea, 0xbf, 0xe5, 0x74, 0x6d, 0x61, 0x53, 0xa8, 0xfe, - 0x7b, 0x4e, 0x57, 0x35, 0x61, 0x6c, 0x27, 0x9f, 0x82, 0x7c, 0xbd, 0xd7, 0x40, 0x54, 0x6e, 0x53, - 0x67, 0x71, 0xc5, 0x7a, 0x0d, 0x33, 0x85, 0x2e, 0xd1, 0xc8, 0x32, 0xe4, 0x1f, 0x51, 0x3f, 0x88, - 0x3d, 0x1e, 0x3a, 0xed, 0x7d, 0x0e, 0x52, 0x09, 0x04, 0x16, 0xb9, 0x13, 0x7b, 0x5d, 0xb1, 0xdd, - 0x9c, 0x4c, 0xf9, 0xba, 0x58, 0x55, 0x3a, 0x02, 0xa2, 0xaa, 0x8a, 0xc4, 0xd2, 0xbf, 0x9b, 0x81, - 0xd2, 0x9a, 0x15, 0x5a, 0x0d, 0x2b, 0x10, 0xf2, 0x7c, 0xf4, 0x3a, 0xf3, 0xe3, 0xca, 0x44, 0xd1, - 0x8f, 0xb3, 0x91, 0x7f, 0xe0, 0xe9, 0x7d, 0x22, 0x3d, 0xbd, 0x19, 0xb6, 0xf7, 0x89, 0xe9, 0xc5, - 0x93, 0x7a, 0xe7, 0xe8, 0x49, 0x95, 0xc4, 0xa4, 0x0a, 0x72, 0x52, 0xf1, 0x54, 0xc8, 0x3b, 0x90, - 0xab, 0x7b, 0xb4, 0x29, 0x9c, 0x88, 0xf4, 0xfd, 0xc9, 0xc9, 0x31, 0x84, 0x47, 0xaf, 0xd7, 0x66, - 0x05, 0x9b, 0x5c, 0xe0, 0xd1, 0xa6, 0x81, 0x64, 0x8a, 0xd1, 0xfc, 0xf6, 0x14, 0x9c, 0x1e, 0x45, - 0x96, 0xde, 0x9c, 0xb4, 0xe7, 0xda, 0x9c, 0xae, 0x42, 0x61, 0x9b, 0xa9, 0x63, 0xd3, 0x6d, 0x0b, - 0xb9, 0x61, 0x24, 0xe1, 0x09, 0x98, 0x11, 0xb5, 0x92, 0xf3, 0x90, 0x7d, 0x68, 0x6c, 0x0a, 0x51, - 0xe5, 0x07, 0xfd, 0x4a, 0xb6, 0xe7, 0x3b, 0x06, 0x83, 0xb1, 0xcd, 0x7d, 0xb5, 0xba, 0x4a, 0xfd, - 0x10, 0x05, 0x34, 0xcb, 0xf5, 0xa4, 0x69, 0x99, 0x4d, 0xea, 0x87, 0xea, 0x2e, 0xc6, 0x91, 0xc8, - 0x35, 0xc8, 0x56, 0x1f, 0xd7, 0x85, 0x44, 0x40, 0x48, 0xa4, 0xfa, 0xb8, 0x5e, 0x9b, 0x11, 0x02, - 0xc8, 0x5a, 0x4f, 0x03, 0x83, 0xe1, 0xa8, 0x6b, 0x34, 0x7d, 0xc8, 0x1a, 0x5d, 0x85, 0x02, 0x0b, - 0x1c, 0xd8, 0xb6, 0x8e, 0xae, 0x50, 0xcc, 0x62, 0x57, 0xc0, 0x8c, 0xa8, 0x95, 0x5c, 0x8e, 0xe2, - 0x90, 0x42, 0xcc, 0x4f, 0xc4, 0x21, 0x32, 0xfa, 0x20, 0xfb, 0x30, 0xb7, 0x76, 0xd0, 0xb5, 0x3a, - 0x4e, 0x53, 0x6c, 0xdc, 0x45, 0xdc, 0xb8, 0x97, 0x0e, 0x59, 0xbc, 0xa5, 0x04, 0x01, 0xdf, 0xcb, - 0x2f, 0x49, 0xb7, 0x61, 0xf3, 0x36, 0x73, 0x68, 0x5f, 0x4f, 0x76, 0xc3, 0xec, 0x47, 0xba, 0x45, - 0x0c, 0x93, 0x62, 0x55, 0x93, 0xe0, 0xd8, 0x7e, 0x7c, 0x01, 0x51, 0xed, 0x47, 0x62, 0x2d, 0x3e, - 0x06, 0x32, 0x3c, 0x9e, 0x11, 0xfb, 0xf6, 0x27, 0xd5, 0x7d, 0x7b, 0x66, 0xe5, 0x8c, 0xe8, 0x6d, - 0xd5, 0xed, 0x74, 0xac, 0xae, 0x8d, 0xb4, 0x8f, 0x56, 0xd4, 0xed, 0xfc, 0x75, 0x5c, 0x3a, 0x72, - 0x1d, 0xa6, 0x0d, 0xda, 0x8a, 0xb5, 0x0d, 0xa3, 0x16, 0x1f, 0x21, 0xea, 0x7a, 0x73, 0x1c, 0xfd, - 0xeb, 0x19, 0x28, 0x08, 0x2b, 0x5e, 0x39, 0xa6, 0x56, 0xfc, 0x46, 0xc2, 0x8a, 0x17, 0x04, 0xa9, - 0xa2, 0x00, 0x2b, 0x47, 0x58, 0xef, 0xb7, 0xa7, 0x60, 0x56, 0x45, 0x67, 0x72, 0xa8, 0xda, 0xb6, - 0xaf, 0xca, 0xc1, 0xb2, 0x6d, 0xdf, 0x40, 0x28, 0x79, 0x0b, 0x60, 0xbb, 0xd7, 0x68, 0x3b, 0x4d, - 0xc4, 0xc9, 0xc4, 0x26, 0xed, 0x21, 0xd4, 0x64, 0xa8, 0x8a, 0x34, 0x14, 0xe4, 0x84, 0x2d, 0x64, - 0x0f, 0xb5, 0x85, 0xaf, 0x41, 0x71, 0xb5, 0x63, 0x0b, 0x15, 0xcf, 0xa1, 0x8a, 0xeb, 0x23, 0x66, - 0xb6, 0x14, 0x21, 0x71, 0xb5, 0xbe, 0x20, 0x26, 0x7a, 0xba, 0xd9, 0xb1, 0x87, 0x55, 0x3a, 0x66, - 0x99, 0x50, 0xe7, 0xa9, 0x5f, 0x42, 0x9d, 0xc9, 0x9b, 0x50, 0x7c, 0x18, 0xd0, 0x9d, 0x5e, 0xb7, - 0x4b, 0xdb, 0xe8, 0x07, 0x0a, 0xb5, 0x32, 0x1b, 0x40, 0x2f, 0xa0, 0x66, 0x88, 0x50, 0x75, 0x00, - 0x11, 0xaa, 0xaa, 0x1b, 0xf9, 0x43, 0x74, 0x63, 0x05, 0x72, 0x55, 0xcf, 0x93, 0x56, 0x1e, 0x39, - 0x24, 0xcf, 0xe3, 0xbb, 0xa9, 0xe5, 0x79, 0xea, 0x04, 0x11, 0x97, 0x50, 0x20, 0x5b, 0xbd, 0x06, - 0xf5, 0xbb, 0x34, 0xa4, 0xc1, 0x6a, 0xbb, 0x17, 0x84, 0x2c, 0x94, 0x00, 0xe4, 0x50, 0x96, 0xb9, - 0x51, 0x1a, 0xa1, 0xf6, 0xd2, 0xa0, 0x5f, 0x39, 0xb7, 0xd7, 0x6b, 0xb0, 0x50, 0x85, 0x93, 0x28, - 0x8c, 0x47, 0x30, 0x5c, 0xac, 0xc3, 0x7c, 0x52, 0xfa, 0x2f, 0xc0, 0x88, 0xbf, 0x90, 0x2b, 0x14, - 0x4a, 0x45, 0xfd, 0x1f, 0x73, 0x90, 0xad, 0x7a, 0xde, 0x11, 0xe9, 0x91, 0xf0, 0xfa, 0x99, 0x11, - 0x5e, 0x3f, 0xa9, 0xa3, 0xd9, 0xe7, 0xd1, 0xd1, 0x47, 0x30, 0xcb, 0xc2, 0xfc, 0xc8, 0xbf, 0x72, - 0xe5, 0xbb, 0x10, 0x4b, 0x7e, 0x49, 0x6d, 0x3e, 0x2c, 0x33, 0x4a, 0xf0, 0x21, 0x66, 0xda, 0x71, - 0xf3, 0x8c, 0xeb, 0x65, 0x85, 0xf1, 0x08, 0x3f, 0x1d, 0x29, 0x61, 0x93, 0x8b, 0xec, 0x10, 0x0f, - 0xbd, 0x01, 0x64, 0xb3, 0x1b, 0xd0, 0x66, 0xcf, 0xa7, 0xf5, 0x3d, 0xc7, 0x7b, 0x44, 0x7d, 0xe7, - 0xc9, 0x81, 0xaa, 0x92, 0x8e, 0x68, 0x35, 0x83, 0x3d, 0xc7, 0x33, 0xf7, 0xb1, 0xdd, 0x18, 0x41, - 0x43, 0x6e, 0x41, 0xde, 0xa0, 0x4f, 0x7d, 0x27, 0xa4, 0x22, 0x78, 0x9f, 0x97, 0xb6, 0xc1, 0xa1, - 0x7c, 0x13, 0xf5, 0xf9, 0x0f, 0xd5, 0xf1, 0x89, 0xf6, 0xc5, 0x5b, 0x70, 0x6a, 0x48, 0x48, 0xcf, - 0x93, 0x9a, 0x7d, 0x98, 0x9b, 0x84, 0x1c, 0x24, 0x73, 0x46, 0x06, 0xb5, 0x1d, 0x9f, 0x36, 0xc3, - 0xb2, 0x76, 0x29, 0x2b, 0x9d, 0x91, 0x2f, 0x60, 0x46, 0xd4, 0xaa, 0x7f, 0x53, 0x83, 0xf9, 0x24, - 0x4b, 0xb2, 0x04, 0xd3, 0x22, 0x51, 0xd2, 0x30, 0x51, 0x62, 0x7b, 0xc1, 0x34, 0x4f, 0x91, 0x12, - 0x89, 0x91, 0xc0, 0x62, 0xe6, 0x2e, 0x38, 0x94, 0x33, 0xd8, 0x17, 0x9a, 0xbb, 0x58, 0x54, 0x43, - 0xb6, 0x11, 0x9d, 0x6d, 0x5e, 0x41, 0xaf, 0x1d, 0x0a, 0x9d, 0x05, 0xc6, 0xd6, 0x47, 0x88, 0x21, - 0x5a, 0xf4, 0x2f, 0x01, 0xec, 0xdc, 0xad, 0x6f, 0xd1, 0x83, 0x6d, 0xcb, 0xc1, 0x10, 0x1b, 0xa3, - 0x1b, 0x0d, 0xa3, 0x1b, 0x74, 0x0a, 0xa9, 0xd0, 0x06, 0xdb, 0xc9, 0x65, 0xc8, 0x6e, 0xd1, 0x03, - 0x94, 0xd3, 0x6c, 0xed, 0xd4, 0xa0, 0x5f, 0x99, 0xdb, 0xa3, 0x4a, 0x28, 0x6f, 0xb0, 0x56, 0xfd, - 0x37, 0x01, 0xbe, 0xf0, 0x78, 0x47, 0xb2, 0x7e, 0x13, 0x8a, 0xdc, 0x2e, 0xb6, 0x84, 0xd0, 0x67, - 0xb9, 0x1e, 0x09, 0x1b, 0x4a, 0xd2, 0xc7, 0xa8, 0x68, 0x7c, 0xbe, 0xb3, 0x6f, 0x85, 0x34, 0xee, - 0x91, 0x1b, 0x1f, 0x87, 0xa6, 0x28, 0x15, 0x64, 0xfd, 0xdb, 0x19, 0x38, 0xc9, 0x86, 0x5b, 0xed, - 0x85, 0xbb, 0xae, 0xef, 0x84, 0x07, 0xc7, 0x76, 0x57, 0xbe, 0x99, 0xd8, 0x95, 0x17, 0xa5, 0x62, - 0xaa, 0x73, 0x9b, 0x68, 0x73, 0xfe, 0xc1, 0x34, 0x2c, 0x8c, 0xa0, 0x22, 0xd7, 0x45, 0xc9, 0x8b, - 0x4b, 0xa5, 0x2c, 0x4b, 0x5a, 0xef, 0xf7, 0x2b, 0xb3, 0x12, 0x7d, 0x27, 0x2e, 0x71, 0xad, 0xc0, - 0x8c, 0xf0, 0xdb, 0xe8, 0x4f, 0xb9, 0xa4, 0xb0, 0xa0, 0x22, 0x9c, 0x3d, 0xaf, 0xf6, 0xa9, 0x48, - 0xe4, 0x16, 0xcc, 0xae, 0xee, 0xd2, 0xe6, 0x9e, 0xd3, 0x6d, 0x6d, 0xd1, 0x83, 0xa0, 0x9c, 0xbd, - 0x94, 0xbd, 0x3a, 0xcb, 0xb7, 0x89, 0xa6, 0x80, 0xb3, 0x95, 0x4c, 0x78, 0x3c, 0x95, 0x80, 0xdc, - 0x84, 0x99, 0xba, 0xd3, 0xea, 0x4a, 0xfa, 0x1c, 0xd2, 0x2f, 0xb2, 0x3c, 0x3f, 0xe0, 0xe0, 0x34, - 0xb9, 0x8a, 0x4e, 0xae, 0xc1, 0x94, 0xe1, 0xb6, 0x29, 0xf7, 0x93, 0xa2, 0xca, 0xe2, 0x33, 0x80, - 0x5a, 0x65, 0x41, 0x0c, 0xb2, 0x01, 0x79, 0xf6, 0xcf, 0x3d, 0xcb, 0x2b, 0x4f, 0xa3, 0x53, 0x25, - 0xd1, 0x5e, 0x8e, 0x50, 0xcf, 0xe9, 0xb6, 0xd4, 0xed, 0xbc, 0x4d, 0xcd, 0x8e, 0xe5, 0x25, 0x1c, - 0x17, 0x47, 0x24, 0x3b, 0x30, 0x13, 0xdb, 0x56, 0x50, 0xce, 0x23, 0xb7, 0x53, 0x82, 0x5b, 0xdc, - 0x52, 0xab, 0x08, 0x66, 0xe7, 0xc2, 0x76, 0xc0, 0x66, 0x61, 0x7a, 0x0c, 0x5f, 0x9d, 0x8a, 0xc2, - 0x26, 0x11, 0x6c, 0x14, 0xc6, 0x07, 0x1b, 0xda, 0x91, 0xc1, 0x86, 0x0d, 0x20, 0x44, 0x54, 0x6d, - 0xb7, 0x44, 0xb5, 0xf3, 0xda, 0x78, 0xd5, 0x5a, 0x8a, 0x91, 0xb1, 0xf0, 0x89, 0x46, 0x28, 0x65, - 0x6f, 0xb5, 0x5b, 0xaa, 0x11, 0xc6, 0xa8, 0x4c, 0x08, 0xb1, 0x17, 0x90, 0x81, 0x83, 0x14, 0x42, - 0xdc, 0x12, 0x0b, 0xe1, 0x37, 0x9e, 0x86, 0xa3, 0x85, 0xa0, 0xb0, 0xd1, 0x1f, 0xc0, 0x7c, 0x72, - 0x38, 0xc9, 0xba, 0xe9, 0x2c, 0x14, 0x8c, 0x7a, 0xd5, 0xac, 0x6f, 0x54, 0x6f, 0x94, 0x34, 0x52, - 0x82, 0x59, 0xf1, 0x6b, 0xc5, 0x5c, 0x79, 0xe3, 0xcd, 0x52, 0x26, 0x01, 0x79, 0xe3, 0xc6, 0x4a, - 0x29, 0xab, 0x1b, 0x30, 0xa3, 0xac, 0x2f, 0x77, 0x9d, 0x1d, 0x37, 0xaa, 0xe0, 0x09, 0xd7, 0xc9, - 0x20, 0x86, 0x68, 0x21, 0x15, 0x98, 0xba, 0xeb, 0x36, 0xad, 0xb6, 0xf0, 0xc1, 0xc5, 0x41, 0xbf, - 0x32, 0xd5, 0x66, 0x00, 0x83, 0xc3, 0xf5, 0xbf, 0xd5, 0xa0, 0xb4, 0xed, 0xbb, 0xfb, 0x0e, 0x73, - 0x01, 0x3b, 0xee, 0x1e, 0xed, 0x3e, 0xba, 0x41, 0x5e, 0x93, 0x9a, 0xc8, 0x77, 0x89, 0x73, 0x8c, - 0x0a, 0x35, 0xf1, 0xfd, 0x7e, 0x05, 0xea, 0x07, 0x41, 0x48, 0x3b, 0xac, 0x5d, 0x6a, 0xa3, 0x52, - 0x08, 0xcd, 0x4c, 0x5e, 0x5c, 0x39, 0xa2, 0x10, 0x5a, 0x81, 0x29, 0x1c, 0x8e, 0x70, 0x59, 0x38, - 0xf2, 0x90, 0x01, 0x0c, 0x0e, 0x57, 0x3c, 0xc6, 0x77, 0x33, 0x43, 0x73, 0x58, 0xf9, 0x48, 0x15, - 0x28, 0x92, 0x93, 0x9b, 0xc8, 0x8b, 0xae, 0xc3, 0xe9, 0x51, 0x54, 0xcf, 0xb9, 0xb4, 0xfa, 0xef, - 0x67, 0x60, 0x9e, 0x07, 0x36, 0xc8, 0x24, 0x38, 0xb6, 0x82, 0xfd, 0x5c, 0x42, 0xb0, 0xe7, 0x65, - 0x66, 0xa5, 0x4c, 0x6d, 0x22, 0xb1, 0xee, 0x02, 0x19, 0xa6, 0x21, 0x86, 0x8c, 0xa0, 0x39, 0x14, - 0x65, 0x1b, 0x57, 0x68, 0xd3, 0xe6, 0x55, 0x3b, 0x23, 0xba, 0x98, 0x0b, 0x90, 0xc8, 0x44, 0xb5, - 0x0e, 0x8c, 0x04, 0x0f, 0xfd, 0x9b, 0x19, 0x98, 0x53, 0x36, 0xa7, 0x63, 0x2b, 0xf8, 0xb7, 0x13, - 0x82, 0x97, 0xd9, 0x98, 0x32, 0xb3, 0x89, 0xe4, 0x7e, 0x07, 0x4e, 0x0d, 0x91, 0xa4, 0xf7, 0x78, - 0x6d, 0x82, 0x3d, 0x9e, 0xc7, 0x5b, 0xfc, 0xf7, 0xaa, 0xdb, 0x7d, 0xe2, 0xb4, 0x8e, 0x6d, 0x2d, - 0x73, 0x4c, 0xbc, 0xa5, 0xce, 0x6d, 0xa2, 0x52, 0xe6, 0x2f, 0xa6, 0x60, 0x61, 0x04, 0x15, 0xa9, - 0x42, 0xa9, 0x4e, 0x03, 0x1c, 0x32, 0x6d, 0xba, 0xbe, 0xed, 0x74, 0x5b, 0x42, 0x42, 0x98, 0x0c, - 0x05, 0xbc, 0xcd, 0xf4, 0x65, 0xa3, 0x31, 0x84, 0x8e, 0x87, 0x3c, 0x9c, 0xf3, 0xe6, 0x9a, 0x10, - 0x1e, 0x3f, 0xe4, 0x11, 0xcb, 0x83, 0x87, 0x3c, 0x12, 0x81, 0xdc, 0x85, 0x85, 0x6d, 0xdf, 0x7d, - 0x76, 0x80, 0x21, 0x55, 0xb0, 0xe1, 0x06, 0xa1, 0x88, 0xc2, 0x18, 0x1d, 0x46, 0x51, 0x1e, 0x6b, - 0x36, 0x31, 0x16, 0x0b, 0x4c, 0xac, 0x13, 0xb2, 0x78, 0xca, 0x18, 0x45, 0x46, 0x3e, 0x03, 0x53, - 0xd5, 0x9e, 0xed, 0x84, 0x42, 0xb4, 0x32, 0x40, 0x42, 0x18, 0x9f, 0x67, 0x6d, 0x4e, 0xc8, 0x65, - 0xca, 0x62, 0x40, 0x83, 0xe3, 0x93, 0x2f, 0x32, 0x55, 0x73, 0x68, 0x37, 0xdc, 0xb4, 0xdb, 0x94, - 0xed, 0x5b, 0x6e, 0x2f, 0x44, 0x21, 0x67, 0x6b, 0x97, 0x07, 0xfd, 0xca, 0x02, 0x3f, 0xd7, 0x30, - 0x1d, 0xbb, 0x4d, 0xcd, 0x90, 0x37, 0x27, 0x12, 0xa0, 0x61, 0x6a, 0xf2, 0x25, 0x38, 0xb3, 0xe6, - 0x04, 0x4d, 0xb7, 0xdb, 0xa5, 0xcd, 0x90, 0x6f, 0x70, 0x36, 0xe6, 0x30, 0x3c, 0x57, 0x65, 0x6c, - 0xcf, 0xd9, 0x11, 0x82, 0xc9, 0x77, 0x46, 0x1b, 0x2b, 0xb6, 0xef, 0xf7, 0x2b, 0xb9, 0x9a, 0xeb, - 0xb6, 0x8d, 0xd1, 0x1c, 0xd8, 0x68, 0xa3, 0xb3, 0xd9, 0xcd, 0x6e, 0x48, 0xfd, 0x7d, 0xab, 0x2d, - 0x8e, 0x0f, 0x71, 0xb4, 0x7b, 0x94, 0x7a, 0xa6, 0xc5, 0x5a, 0x4d, 0x47, 0x34, 0x27, 0x47, 0x3b, - 0x44, 0x4d, 0x6e, 0x2b, 0x2c, 0x57, 0xdd, 0x5e, 0x37, 0xbc, 0x67, 0x3d, 0xc3, 0x28, 0x2e, 0xcb, - 0xb3, 0x21, 0x85, 0x65, 0x93, 0x35, 0x9b, 0x1d, 0xeb, 0x99, 0x31, 0x4c, 0x42, 0x3e, 0x0d, 0x45, - 0x8c, 0x31, 0x58, 0x8c, 0x86, 0xa1, 0x5b, 0x01, 0x4d, 0x07, 0x30, 0xfe, 0x30, 0xad, 0x5e, 0xb8, - 0x1b, 0x4d, 0x2e, 0x46, 0x24, 0x5f, 0x85, 0x33, 0x42, 0x8f, 0x56, 0xdd, 0x6e, 0xe8, 0xbb, 0x6d, - 0xb9, 0x04, 0x80, 0x23, 0x78, 0x85, 0xc9, 0x4a, 0xea, 0x5e, 0x93, 0x63, 0x8c, 0x5c, 0x86, 0xd1, - 0x5c, 0xf4, 0x6f, 0x17, 0x60, 0x46, 0xd1, 0x01, 0x96, 0x4d, 0x2a, 0x59, 0x05, 0x66, 0x93, 0x4c, - 0x51, 0xd4, 0x6c, 0x12, 0x43, 0xb7, 0xb8, 0xc8, 0x9a, 0x39, 0xba, 0xc8, 0x4a, 0xee, 0x42, 0x09, - 0x3b, 0x11, 0x63, 0x08, 0xe2, 0x5a, 0xfd, 0xa5, 0x41, 0xbf, 0x72, 0x01, 0xf5, 0xcd, 0x14, 0xb3, - 0x08, 0xcc, 0x9e, 0xef, 0x28, 0x3c, 0x86, 0x28, 0xc9, 0x8f, 0x34, 0x98, 0x47, 0xe0, 0xfa, 0x3e, - 0xed, 0x86, 0xc8, 0x8c, 0x2b, 0xf5, 0xd9, 0xa5, 0xe8, 0xa6, 0x43, 0x3d, 0xf4, 0x9d, 0x6e, 0xeb, - 0x11, 0x4b, 0xfb, 0x83, 0x5a, 0x83, 0x29, 0xf6, 0xcf, 0xfa, 0x95, 0x9b, 0x1f, 0xe4, 0xf6, 0x84, - 0x60, 0x15, 0x0c, 0xfa, 0x95, 0x45, 0x3e, 0x50, 0x8a, 0xdd, 0xa6, 0x86, 0x99, 0x1a, 0x11, 0xb9, - 0x2d, 0xc6, 0xb8, 0x63, 0x35, 0xda, 0x14, 0xfd, 0xf1, 0x14, 0x4e, 0xf8, 0x62, 0xcc, 0x27, 0x64, - 0x4d, 0xe8, 0x93, 0x87, 0xf8, 0x44, 0x54, 0xe4, 0xd7, 0xe0, 0xdc, 0x7a, 0x97, 0xfd, 0x62, 0x0b, - 0xe7, 0x74, 0x7b, 0x6e, 0x2f, 0xa8, 0x59, 0xcd, 0xbd, 0x9e, 0x17, 0x08, 0x6b, 0x41, 0x09, 0x36, - 0xa3, 0x46, 0xb3, 0xc1, 0x5b, 0x15, 0x96, 0xe3, 0x18, 0x90, 0x0d, 0x38, 0xc5, 0x9b, 0xaa, 0xbd, - 0xd0, 0xad, 0x37, 0xad, 0x36, 0xf3, 0x69, 0x79, 0xe4, 0x8a, 0xfe, 0xc5, 0xea, 0x85, 0xae, 0x19, - 0x70, 0xb8, 0xc2, 0x6f, 0x98, 0x88, 0x6c, 0xc2, 0x49, 0x83, 0x5a, 0xf6, 0x3d, 0xeb, 0xd9, 0xaa, - 0xe5, 0x59, 0x4d, 0x27, 0x3c, 0x10, 0x16, 0x52, 0x19, 0xf4, 0x2b, 0x2f, 0xf9, 0xd4, 0xb2, 0x99, - 0x55, 0x98, 0x4d, 0xd1, 0xa8, 0x30, 0x4b, 0xd3, 0x45, 0xac, 0x9c, 0x6e, 0xc4, 0xaa, 0x98, 0x66, - 0xe5, 0x74, 0xc7, 0xb3, 0x8a, 0xe9, 0x24, 0xab, 0x1d, 0xcb, 0x6f, 0xd1, 0x10, 0x75, 0x01, 0xad, - 0x46, 0x53, 0x58, 0x85, 0xd8, 0x66, 0x62, 0x7d, 0x28, 0xcd, 0x4a, 0xa1, 0x63, 0x1a, 0xfc, 0xd8, - 0x77, 0x42, 0xaa, 0xce, 0x70, 0x06, 0x87, 0x85, 0xf2, 0xc7, 0x82, 0xd2, 0xb8, 0x29, 0x0e, 0x51, - 0xc6, 0xdc, 0x94, 0x49, 0xce, 0x0e, 0x71, 0x1b, 0x3d, 0xcb, 0x21, 0xca, 0x88, 0x9b, 0x3a, 0xcf, - 0x39, 0x9c, 0xa7, 0xc2, 0x6d, 0xcc, 0x44, 0x87, 0x28, 0xf5, 0xff, 0xd6, 0x94, 0x4b, 0x27, 0xc7, - 0x34, 0x16, 0x78, 0x33, 0x11, 0x0b, 0x9c, 0x16, 0xa4, 0xd1, 0xac, 0x58, 0xdb, 0xa8, 0x28, 0x40, - 0x3f, 0x09, 0x73, 0x09, 0x24, 0xfd, 0x87, 0x19, 0x38, 0x6d, 0xd0, 0x80, 0x86, 0xdb, 0x56, 0x10, - 0x3c, 0x75, 0x7d, 0x9b, 0xc7, 0xac, 0xc7, 0x35, 0x46, 0xaa, 0x26, 0xe4, 0x52, 0x89, 0x8a, 0xba, - 0xe9, 0x09, 0x4e, 0x14, 0x28, 0xfd, 0x58, 0x83, 0xf2, 0x38, 0x52, 0x26, 0x9f, 0x87, 0x01, 0x4d, - 0x9c, 0x20, 0xf5, 0x02, 0xea, 0x1b, 0x08, 0xe5, 0x85, 0xfb, 0xbb, 0xc9, 0xc2, 0x7d, 0xdb, 0x60, - 0x30, 0x96, 0x3c, 0xaf, 0xfa, 0x14, 0xef, 0x8d, 0xe4, 0x26, 0x4f, 0x9e, 0x9b, 0x9c, 0x24, 0x9d, - 0x3c, 0x0b, 0x4e, 0xfa, 0x9f, 0x67, 0xe0, 0xa5, 0x11, 0x43, 0xa5, 0x4d, 0x9f, 0x86, 0xc1, 0xb1, - 0x5d, 0xcd, 0x8d, 0xc4, 0x6a, 0x5e, 0x19, 0xbf, 0x9a, 0x7c, 0x9e, 0x13, 0x2d, 0xea, 0xdf, 0x6b, - 0x50, 0x39, 0x82, 0x03, 0xb9, 0x0c, 0xd3, 0x0f, 0x76, 0xb6, 0x65, 0x4d, 0x58, 0x4c, 0xce, 0xf5, - 0x30, 0xfa, 0x34, 0x44, 0x13, 0x79, 0x0d, 0xa6, 0xbf, 0x68, 0xac, 0xba, 0xb6, 0xac, 0x35, 0x62, - 0x90, 0xfc, 0xae, 0x6f, 0x36, 0x93, 0xb7, 0x9f, 0x04, 0x92, 0xba, 0xec, 0xd9, 0x17, 0xb6, 0xec, - 0x2c, 0xb9, 0xa9, 0x36, 0x9b, 0x34, 0x08, 0x0c, 0xfa, 0x6e, 0x8f, 0x06, 0xe1, 0x47, 0x2c, 0xb9, - 0x49, 0xcc, 0x6d, 0xa2, 0xe5, 0xfd, 0x93, 0x69, 0x58, 0x18, 0x41, 0x75, 0x84, 0xb9, 0x56, 0x64, - 0x91, 0x44, 0xa9, 0x9a, 0x61, 0x91, 0x44, 0x56, 0xbc, 0x7e, 0x45, 0xde, 0x9d, 0xcb, 0x62, 0x45, - 0x72, 0x21, 0x52, 0x45, 0xde, 0x07, 0x6b, 0x3a, 0xf4, 0x42, 0xdd, 0x87, 0x61, 0xf4, 0x6a, 0x19, - 0x6e, 0xea, 0x85, 0x95, 0xe1, 0x6a, 0x30, 0x27, 0x66, 0x65, 0x50, 0x2b, 0x88, 0x6e, 0x7e, 0x5c, - 0x18, 0xf4, 0x2b, 0x65, 0x9f, 0x37, 0x98, 0x3e, 0xb6, 0xa8, 0xe7, 0x74, 0x09, 0x12, 0xce, 0x23, - 0x70, 0xdb, 0xfb, 0x54, 0xf0, 0xc8, 0xab, 0x3c, 0xb0, 0x61, 0x24, 0x0f, 0x85, 0x84, 0xfc, 0xa5, - 0x06, 0x44, 0x40, 0xaa, 0xdd, 0xae, 0x28, 0x0f, 0x07, 0xa2, 0xb8, 0x7c, 0x26, 0x8e, 0x83, 0xf9, - 0x71, 0x15, 0x0f, 0x83, 0x6d, 0x11, 0x06, 0x7f, 0xee, 0x03, 0x85, 0xc1, 0x3b, 0xbe, 0xe5, 0x84, - 0x2c, 0x0a, 0x7e, 0x59, 0x8e, 0xd1, 0x8a, 0x3b, 0x56, 0x4f, 0x8a, 0x87, 0x87, 0x45, 0x7e, 0xac, - 0xc1, 0x29, 0x5e, 0x4c, 0x53, 0x07, 0x5b, 0x3c, 0x6c, 0xb0, 0xcd, 0x17, 0x33, 0xd8, 0x0b, 0x01, - 0x76, 0x3b, 0x66, 0xac, 0xc3, 0x83, 0xd2, 0xbf, 0xae, 0xa5, 0x2c, 0xe4, 0xb6, 0xd3, 0x0e, 0xa9, - 0x4f, 0xce, 0xe2, 0x45, 0x54, 0x6e, 0x1f, 0xd3, 0x83, 0x7e, 0x25, 0xe3, 0xd8, 0x46, 0x66, 0x73, - 0x2d, 0xb2, 0x9c, 0xcc, 0x48, 0xcb, 0xf9, 0xf4, 0x04, 0x86, 0x81, 0xe6, 0x84, 0x86, 0x21, 0xcc, - 0x41, 0xb7, 0x80, 0xf0, 0x21, 0xb0, 0x10, 0xaf, 0xe1, 0xb4, 0x9d, 0xd0, 0xa1, 0x01, 0xd9, 0x82, - 0x92, 0xa0, 0x63, 0xd1, 0xb7, 0x5a, 0xb5, 0x14, 0xe1, 0x6c, 0xd4, 0x66, 0xa6, 0x8f, 0x49, 0x86, - 0x08, 0xf5, 0xef, 0x68, 0x70, 0x7e, 0xb8, 0x0f, 0x81, 0xc6, 0xb2, 0x40, 0xc5, 0x1d, 0x60, 0x16, - 0xc8, 0x26, 0xa5, 0x66, 0x81, 0x38, 0xbd, 0x51, 0x43, 0xca, 0x60, 0xfe, 0xf0, 0x01, 0x86, 0xf4, - 0x7b, 0x19, 0x98, 0xdd, 0x6e, 0xf7, 0x5a, 0x4e, 0x77, 0xcd, 0x0a, 0xad, 0x63, 0xeb, 0xaa, 0xdf, - 0x4a, 0xb8, 0xea, 0xa8, 0xe8, 0x19, 0x4d, 0x6c, 0x22, 0x3f, 0xfd, 0x07, 0x1a, 0x9c, 0x8c, 0x49, - 0xf8, 0xe1, 0xf7, 0x06, 0xe4, 0xd8, 0x0f, 0x51, 0x4d, 0xbd, 0x34, 0xc4, 0x18, 0xb1, 0x96, 0xa2, - 0xff, 0xf8, 0xb2, 0xa5, 0x6e, 0x31, 0x22, 0x87, 0xc5, 0xcf, 0x40, 0x31, 0x66, 0xfb, 0x3c, 0x17, - 0xa6, 0xff, 0x4a, 0x83, 0x52, 0x7a, 0x26, 0x64, 0x0b, 0xf2, 0x8c, 0x93, 0x43, 0x65, 0xa1, 0xf7, - 0xe3, 0x63, 0xe6, 0xbc, 0x24, 0xd0, 0xf8, 0xf0, 0x50, 0xf8, 0x94, 0x43, 0x0c, 0xc9, 0x61, 0xd1, - 0x80, 0x59, 0x15, 0x6b, 0xc4, 0xe8, 0xae, 0x27, 0x4f, 0xfc, 0xcf, 0x8e, 0x96, 0x83, 0x3a, 0xea, - 0x3f, 0x4a, 0x8c, 0x5a, 0xd8, 0xf3, 0xa4, 0x37, 0x53, 0x57, 0xa0, 0x20, 0xef, 0xb4, 0xaa, 0x7a, - 0xe6, 0x0b, 0x58, 0xe2, 0x94, 0x4e, 0xc0, 0xc8, 0x75, 0x98, 0xe6, 0xfd, 0x09, 0x3d, 0xc3, 0xe2, - 0x88, 0x87, 0x10, 0x35, 0xf4, 0xe1, 0x38, 0xfa, 0x1f, 0x67, 0xe1, 0x6c, 0x3c, 0x3c, 0x7e, 0x4f, - 0x77, 0xdb, 0xf2, 0xad, 0x4e, 0x70, 0x84, 0x05, 0x5c, 0x1d, 0x1a, 0x9a, 0xb8, 0xbf, 0xc0, 0x61, - 0xca, 0x80, 0xf4, 0xd4, 0x80, 0xf0, 0x68, 0x8c, 0x0f, 0x48, 0x0e, 0x83, 0x6c, 0x41, 0xb6, 0x4e, - 0x43, 0x71, 0xdb, 0xe5, 0xca, 0x90, 0x54, 0xd5, 0x71, 0x2d, 0xd5, 0x69, 0xc8, 0x17, 0x11, 0xef, - 0x11, 0x04, 0x54, 0xbd, 0x6d, 0xc0, 0xb8, 0x90, 0xc7, 0x30, 0xbd, 0xfe, 0xcc, 0xa3, 0xcd, 0x50, - 0x5c, 0x72, 0xb9, 0x76, 0x38, 0x3f, 0x8e, 0xab, 0x5c, 0xa5, 0xa1, 0x08, 0x50, 0x85, 0xc5, 0x51, - 0x16, 0xdf, 0x84, 0x82, 0xec, 0xfc, 0xb9, 0xee, 0x93, 0xbc, 0x05, 0x33, 0x4a, 0x27, 0xcf, 0xa5, - 0xf4, 0xff, 0xab, 0xc1, 0x34, 0xf3, 0x50, 0xc7, 0xd6, 0x23, 0xbd, 0x9e, 0xf0, 0x48, 0xa7, 0x94, - 0xa3, 0xf1, 0x89, 0x7c, 0x51, 0x5f, 0x03, 0x88, 0x91, 0xc9, 0x1d, 0xc8, 0x3f, 0xf0, 0xf8, 0x06, - 0xae, 0x25, 0x4a, 0xc9, 0x0c, 0x47, 0xb4, 0xd4, 0xce, 0xcb, 0x70, 0xca, 0xf5, 0xd2, 0x7b, 0xae, - 0xa4, 0x26, 0x6b, 0x30, 0x55, 0x6d, 0xb7, 0xdd, 0xa7, 0xa9, 0xab, 0x3b, 0x8c, 0xcd, 0xaa, 0xdb, - 0xb5, 0x1d, 0xce, 0xe9, 0x9c, 0xe0, 0x74, 0xd2, 0x62, 0xb8, 0x6a, 0xe8, 0x88, 0xc4, 0x2c, 0xa5, - 0x5d, 0xa3, 0x5d, 0x79, 0x8d, 0x7d, 0x0c, 0x93, 0xb3, 0x82, 0xc9, 0xbc, 0x4d, 0xbb, 0x07, 0x09, - 0x77, 0x48, 0xbb, 0x07, 0xfa, 0x4f, 0xf3, 0xfc, 0x20, 0x59, 0x0e, 0xec, 0x1d, 0x98, 0xbd, 0xed, - 0xfa, 0x4f, 0x2d, 0xdf, 0xae, 0xb6, 0x68, 0x97, 0xdf, 0xac, 0x29, 0xe0, 0xd9, 0xf9, 0xdc, 0x13, - 0x0e, 0x37, 0x2d, 0xd6, 0x10, 0x95, 0x6b, 0x13, 0xe8, 0xe4, 0x01, 0xcc, 0xdd, 0xb3, 0x9e, 0x89, - 0x82, 0xe5, 0xce, 0x0e, 0x4f, 0x73, 0xb3, 0xb5, 0x6b, 0x83, 0x7e, 0xe5, 0x7c, 0xc7, 0x7a, 0x26, - 0xeb, 0x9c, 0x66, 0x18, 0xb6, 0xc7, 0x3c, 0xa6, 0x48, 0xd2, 0x13, 0x07, 0xe6, 0xb7, 0x5d, 0x3f, - 0x14, 0x9d, 0x38, 0xdd, 0x96, 0x98, 0x6c, 0x49, 0x4c, 0x96, 0x8d, 0x01, 0xa3, 0xa6, 0xda, 0xf2, - 0x7b, 0xfd, 0x8a, 0xf6, 0xb3, 0x7e, 0x05, 0x18, 0x88, 0x4f, 0x87, 0xf5, 0xca, 0xa2, 0x24, 0xf3, - 0x49, 0x44, 0xae, 0x56, 0x1b, 0x93, 0x8c, 0xc9, 0x3b, 0x70, 0x6a, 0x95, 0xfa, 0xa1, 0xf3, 0xc4, - 0x69, 0x5a, 0x21, 0xbd, 0xed, 0xfa, 0x1d, 0x2b, 0x14, 0xcf, 0x51, 0xf0, 0x65, 0x58, 0x93, 0x72, - 0x4e, 0x1d, 0x2b, 0x34, 0x86, 0x31, 0xc9, 0x97, 0xc7, 0x9f, 0x15, 0xbc, 0xc6, 0x22, 0xc7, 0x11, - 0x67, 0x05, 0x63, 0x44, 0x30, 0xe2, 0xd4, 0xa0, 0x75, 0xf8, 0xa9, 0xc1, 0x0d, 0x71, 0x81, 0xe2, - 0x63, 0x63, 0x4e, 0x0e, 0x12, 0x1d, 0x1d, 0x7a, 0x86, 0xb0, 0x02, 0xd9, 0xda, 0xf6, 0x6d, 0xbc, - 0xfb, 0x21, 0x0a, 0xd4, 0xb4, 0xbb, 0x6b, 0x75, 0x9b, 0xd4, 0x8e, 0x4f, 0x77, 0x54, 0x87, 0x57, - 0xdb, 0xbe, 0x4d, 0x2c, 0x58, 0xd8, 0xa6, 0x7e, 0xc7, 0x09, 0x7f, 0xf5, 0xc6, 0x0d, 0x65, 0xa1, - 0x0a, 0x38, 0xb4, 0x65, 0x31, 0xb4, 0x8a, 0x87, 0x28, 0xe6, 0xb3, 0x1b, 0x37, 0x46, 0x2e, 0x47, - 0x34, 0xb0, 0x51, 0xbc, 0xc8, 0x3a, 0xcc, 0xdf, 0xb3, 0x9e, 0xad, 0xf2, 0xf1, 0x46, 0x01, 0x74, - 0xb6, 0xf6, 0xb2, 0x54, 0xac, 0x66, 0xdc, 0xa4, 0x2e, 0x71, 0x92, 0x88, 0xdc, 0x84, 0x99, 0x58, - 0xbd, 0x02, 0x71, 0x8c, 0x80, 0xe5, 0x5e, 0x45, 0x39, 0x13, 0x97, 0x38, 0x14, 0x74, 0xf2, 0x30, - 0xca, 0x7f, 0x78, 0xf4, 0x88, 0x45, 0xd0, 0x62, 0x6d, 0x59, 0xcd, 0x7f, 0x2c, 0x6c, 0x49, 0x4c, - 0xeb, 0x64, 0x14, 0xf1, 0xfa, 0x56, 0x48, 0x5b, 0x71, 0x4a, 0xc4, 0xb9, 0x28, 0x69, 0xd5, 0xb6, - 0xef, 0x76, 0xbc, 0x10, 0xab, 0xa1, 0xa9, 0xb4, 0xca, 0xc3, 0x96, 0x11, 0x69, 0x15, 0x27, 0xd1, - 0x7f, 0x91, 0x87, 0xf9, 0xa4, 0xdd, 0xb3, 0x8d, 0xf8, 0xae, 0xdb, 0x72, 0xba, 0x32, 0x50, 0xe6, - 0xd7, 0x34, 0x11, 0x92, 0x78, 0xc0, 0x86, 0x10, 0xf2, 0x09, 0x80, 0xa8, 0xfa, 0x27, 0x73, 0x5d, - 0xf1, 0xdc, 0x4e, 0x69, 0x20, 0x5f, 0x03, 0xb8, 0xef, 0xda, 0x54, 0x5c, 0xe2, 0xcc, 0x1e, 0x96, - 0xc4, 0xbc, 0x22, 0x92, 0x18, 0xf1, 0x44, 0x6e, 0xd0, 0xaf, 0x9c, 0xe9, 0xba, 0x36, 0x1d, 0xbe, - 0x98, 0xac, 0x70, 0x24, 0x6f, 0xc3, 0x94, 0xd1, 0x6b, 0x53, 0x79, 0xf1, 0x74, 0x46, 0xba, 0xb4, - 0x5e, 0x9b, 0xc6, 0xde, 0xd0, 0xef, 0xa5, 0x2f, 0x42, 0x31, 0x00, 0xb9, 0x05, 0xb0, 0xd5, 0x6b, - 0xd0, 0x3b, 0xbe, 0xdb, 0xf3, 0xe4, 0xc5, 0x29, 0x0c, 0xc5, 0xf7, 0xa2, 0xeb, 0xbb, 0x66, 0x0b, - 0x1b, 0xd5, 0xce, 0x63, 0x12, 0xf2, 0x00, 0xf2, 0x42, 0xaa, 0xe2, 0x11, 0xdf, 0xc5, 0x51, 0xb5, - 0x06, 0xc5, 0xb5, 0x8a, 0x9b, 0xa0, 0x08, 0x4e, 0xde, 0x04, 0xe5, 0xa9, 0xc4, 0x4d, 0x28, 0x32, - 0xf6, 0x2c, 0x5d, 0x08, 0x84, 0x49, 0xe1, 0x11, 0x88, 0x32, 0x20, 0x96, 0x5a, 0x24, 0x6e, 0x69, - 0x47, 0x04, 0xe4, 0xcb, 0x50, 0xac, 0x7a, 0x9e, 0x10, 0xf5, 0xa1, 0xc9, 0xed, 0x95, 0x21, 0x51, - 0x9f, 0xb6, 0x3c, 0x6f, 0xc4, 0x15, 0xf0, 0x88, 0x1f, 0x69, 0x45, 0x37, 0x0a, 0xa2, 0x97, 0x14, - 0x87, 0x74, 0xf0, 0xea, 0x50, 0x07, 0x65, 0x79, 0x6e, 0x3b, 0xfc, 0x74, 0x22, 0xc1, 0x97, 0x78, - 0x50, 0x8a, 0xaf, 0x4f, 0x8b, 0xbe, 0xe0, 0xb0, 0xbe, 0x5e, 0x1b, 0xea, 0x4b, 0x5d, 0xc0, 0xa1, - 0xee, 0x86, 0xb8, 0x13, 0x1b, 0xe6, 0xe5, 0x43, 0x10, 0xd1, 0xdf, 0xcc, 0x61, 0xfd, 0x7d, 0x62, - 0xa8, 0xbf, 0x05, 0xbb, 0x31, 0xdc, 0x4f, 0x8a, 0x27, 0xb9, 0x09, 0x73, 0x12, 0x82, 0xf6, 0x51, - 0x9e, 0xc5, 0xf5, 0xc5, 0xb0, 0xc7, 0x6e, 0xe0, 0xc9, 0x56, 0xf2, 0xba, 0xb2, 0x8a, 0xac, 0x52, - 0x73, 0xed, 0x98, 0x4b, 0x50, 0xa7, 0xb5, 0x22, 0x89, 0xac, 0xff, 0x5d, 0x06, 0xce, 0x8d, 0xd1, - 0xc9, 0xf8, 0xe6, 0xa0, 0x76, 0xe4, 0xcd, 0x41, 0x87, 0xe9, 0x80, 0xe5, 0x74, 0x82, 0x1d, 0x37, - 0x2e, 0x71, 0xc5, 0xd9, 0x55, 0xb2, 0x07, 0x86, 0x28, 0x6f, 0x13, 0x7e, 0x4c, 0x58, 0xe2, 0xf9, - 0x26, 0x92, 0x9b, 0xa1, 0x3b, 0x94, 0xe2, 0x26, 0x39, 0x93, 0xef, 0x6b, 0x30, 0xa3, 0x96, 0x3f, - 0x0e, 0xf5, 0x1c, 0x5f, 0x79, 0x31, 0xe5, 0x8f, 0x33, 0xa3, 0xeb, 0x1e, 0xea, 0x38, 0x58, 0x7a, - 0x74, 0x7e, 0xec, 0x3c, 0x99, 0x2c, 0xf1, 0xb7, 0xfa, 0x2c, 0x16, 0xa7, 0xac, 0xca, 0x12, 0x31, - 0x18, 0xea, 0xa3, 0x38, 0x84, 0xe6, 0xa8, 0xe9, 0xf3, 0x26, 0x8e, 0x11, 0xaf, 0x50, 0xf6, 0xa8, - 0x15, 0xd2, 0x7f, 0xaa, 0x41, 0x8e, 0x39, 0x37, 0xf2, 0x06, 0x14, 0x65, 0x42, 0xa3, 0x5e, 0xd7, - 0x5a, 0x90, 0xf9, 0x4e, 0xc2, 0xca, 0x23, 0x4c, 0x1c, 0x15, 0xf5, 0x1b, 0xd2, 0xa1, 0xf3, 0x51, - 0x31, 0x40, 0x62, 0x54, 0x0c, 0xc0, 0x50, 0x1f, 0xef, 0x52, 0x5f, 0x3e, 0x4d, 0x41, 0xd4, 0xa7, - 0x0c, 0xa0, 0xa2, 0x22, 0x06, 0x59, 0x86, 0x7c, 0x55, 0xec, 0xc2, 0x39, 0xe4, 0x8b, 0x7e, 0xd0, - 0x1a, 0xda, 0x7d, 0x25, 0x96, 0xfe, 0x31, 0x28, 0x46, 0x71, 0x1a, 0x4b, 0x36, 0xb8, 0xa4, 0x30, - 0xb4, 0x14, 0x42, 0xc1, 0x44, 0x83, 0x29, 0xf7, 0xb1, 0xbd, 0xdb, 0x34, 0x3a, 0xd1, 0x60, 0x53, - 0x9a, 0xe8, 0x52, 0xd3, 0x8f, 0xa6, 0x01, 0x62, 0x64, 0xd2, 0x80, 0xf9, 0x07, 0x9b, 0x6b, 0xab, - 0x9b, 0x36, 0xed, 0x86, 0x58, 0x9d, 0x4a, 0xdd, 0x23, 0x5b, 0x7f, 0x16, 0x52, 0xbf, 0x6b, 0xb5, - 0x05, 0xc2, 0x41, 0x6c, 0x92, 0xae, 0x63, 0x37, 0x4d, 0x27, 0xa2, 0x53, 0x3d, 0x58, 0x92, 0x23, - 0xeb, 0xa3, 0x5e, 0xbd, 0x77, 0x57, 0xe9, 0x23, 0x33, 0x61, 0x1f, 0x81, 0xd5, 0x69, 0x8f, 0xe9, - 0x23, 0xc9, 0x91, 0xec, 0x42, 0xe9, 0x0e, 0x1a, 0xb1, 0xd2, 0x4b, 0xf6, 0xf0, 0x5e, 0x2e, 0x8b, - 0x5e, 0x5e, 0xe2, 0xd6, 0x3f, 0xba, 0x9f, 0x21, 0xae, 0xb1, 0x55, 0xe5, 0x8e, 0xf4, 0x7b, 0xbf, - 0xab, 0xc1, 0x34, 0xf7, 0x12, 0x62, 0xb5, 0xc6, 0xf8, 0xa1, 0xc7, 0x2f, 0xc6, 0x0f, 0x95, 0x42, - 0xfc, 0x4f, 0x0d, 0xba, 0x78, 0x1b, 0x59, 0x83, 0xe9, 0x7a, 0x68, 0x85, 0x3d, 0xf9, 0xd1, 0x00, - 0x99, 0x4d, 0x62, 0x4c, 0xc6, 0x5b, 0x6a, 0x65, 0x21, 0x8e, 0x52, 0x80, 0xbf, 0x55, 0x2e, 0x1c, - 0x43, 0xfd, 0x94, 0x44, 0xfe, 0x97, 0xfc, 0x94, 0xc4, 0x5d, 0x28, 0x8a, 0x13, 0x84, 0xda, 0x81, - 0x08, 0x39, 0x64, 0xa2, 0x15, 0xc1, 0x95, 0x67, 0x66, 0x1c, 0x64, 0x36, 0x12, 0x4f, 0x21, 0x22, - 0x44, 0xf2, 0x20, 0x7d, 0xe9, 0x27, 0x5e, 0xf5, 0x08, 0x2e, 0x4e, 0xd7, 0xf8, 0x6d, 0xa2, 0xf8, - 0x36, 0x90, 0xca, 0x30, 0xc2, 0xd5, 0xbf, 0xa5, 0x41, 0x29, 0xad, 0x2f, 0x2c, 0xa6, 0x17, 0x21, - 0xbe, 0xeb, 0x47, 0x55, 0x6a, 0x8c, 0xe9, 0x9b, 0x12, 0x9c, 0xfc, 0x94, 0x85, 0x8a, 0x4e, 0x56, - 0xa0, 0xc0, 0xcc, 0xae, 0x1b, 0x3f, 0x0c, 0x40, 0x7f, 0xd2, 0x13, 0x30, 0xb5, 0xc4, 0x25, 0xf1, - 0x14, 0xab, 0xfd, 0x9b, 0x0c, 0xcc, 0x28, 0x8b, 0x45, 0xae, 0x41, 0x61, 0x33, 0xb8, 0xeb, 0x36, - 0xf7, 0xa8, 0x2d, 0x32, 0x67, 0xfc, 0x52, 0x88, 0x13, 0x98, 0x6d, 0x04, 0x1a, 0x51, 0x33, 0x8b, - 0xfa, 0xf9, 0x7f, 0xf7, 0x68, 0x10, 0x58, 0x2d, 0xd9, 0x3b, 0x46, 0xfd, 0x1c, 0xd9, 0xec, 0xf0, - 0x16, 0x75, 0x57, 0x4d, 0x90, 0x90, 0xaf, 0x02, 0x70, 0x00, 0x5b, 0xdf, 0x09, 0xce, 0x0e, 0xa5, - 0x01, 0x9f, 0x11, 0x1d, 0xb0, 0x34, 0x34, 0x75, 0xd8, 0xa3, 0x30, 0xc4, 0x4f, 0x19, 0xb8, 0xcd, - 0xbd, 0xc9, 0xbf, 0x53, 0x12, 0x7f, 0xca, 0xc0, 0x6d, 0xee, 0x99, 0xa3, 0x4f, 0x93, 0x54, 0x96, - 0xfa, 0x3f, 0x69, 0x8a, 0xc2, 0x91, 0xfb, 0x50, 0x8c, 0x96, 0x46, 0xd4, 0x57, 0x16, 0xa2, 0x37, - 0x4d, 0x02, 0x6e, 0xd0, 0x27, 0xb5, 0x97, 0x44, 0x4a, 0xb9, 0x10, 0x2d, 0x70, 0x42, 0xff, 0x24, - 0x90, 0x7c, 0x1e, 0x72, 0x28, 0x98, 0xa3, 0x2f, 0xa2, 0x4b, 0xc7, 0x9e, 0x63, 0x12, 0xc1, 0x61, - 0x22, 0x25, 0xf9, 0x94, 0x38, 0x0b, 0xc8, 0x26, 0x1e, 0x82, 0x31, 0x10, 0x1b, 0x47, 0xe4, 0xd1, - 0xe3, 0x43, 0x0f, 0xf5, 0x59, 0xb8, 0x06, 0x0b, 0x0f, 0x57, 0x6e, 0x1b, 0xb4, 0xe5, 0x04, 0x21, - 0xcf, 0xec, 0x59, 0x14, 0x47, 0xce, 0x43, 0xd6, 0xb0, 0x9e, 0x8a, 0x27, 0x45, 0x78, 0xfe, 0xef, - 0x5b, 0x4f, 0x0d, 0x06, 0x23, 0xd7, 0xa1, 0xb8, 0x45, 0x0f, 0x36, 0xac, 0xae, 0xdd, 0xa6, 0xe2, - 0xe9, 0x10, 0xde, 0x91, 0xdc, 0xa3, 0x07, 0xe6, 0x2e, 0x42, 0x8d, 0x18, 0x01, 0x0b, 0x9b, 0xbd, - 0xc6, 0x16, 0xe5, 0xf5, 0x9f, 0x59, 0x51, 0xd8, 0xec, 0x35, 0xf0, 0x24, 0x9a, 0xb7, 0xe8, 0xff, - 0x92, 0x81, 0x52, 0xda, 0xd6, 0xc8, 0x2d, 0x98, 0x95, 0x27, 0xdc, 0x1b, 0x56, 0xb0, 0x2b, 0x86, - 0x82, 0x6f, 0x5b, 0x3c, 0x01, 0x37, 0x77, 0xad, 0x40, 0x35, 0xc2, 0x04, 0x01, 0xdb, 0x83, 0x77, - 0xc4, 0x29, 0xb8, 0x62, 0x33, 0xa1, 0x1b, 0x7a, 0xa9, 0xd7, 0x4d, 0x12, 0x8d, 0xd8, 0x70, 0x32, - 0x25, 0x8b, 0x48, 0x5d, 0x85, 0x4c, 0x87, 0x25, 0xc5, 0x73, 0xa5, 0xde, 0xca, 0x13, 0xd3, 0x57, - 0x5a, 0xd4, 0x8b, 0x4a, 0x29, 0x22, 0xf2, 0x16, 0xc0, 0xc3, 0x95, 0xdb, 0x78, 0xe9, 0x90, 0xfa, - 0xa8, 0xaf, 0x73, 0xfc, 0xd9, 0x07, 0x63, 0xd2, 0xe4, 0x60, 0x35, 0xf7, 0x8b, 0x91, 0xc9, 0x1b, - 0x90, 0xbd, 0x77, 0xbb, 0x2a, 0x2a, 0xb6, 0xd2, 0xe7, 0xdd, 0xbb, 0x5d, 0x5d, 0xa3, 0xfb, 0x4e, - 0x93, 0xf2, 0x5a, 0x6f, 0xe7, 0x89, 0x7a, 0x9c, 0xc0, 0xf0, 0xf5, 0xff, 0xca, 0x40, 0x31, 0xc2, - 0x22, 0x04, 0x30, 0x52, 0x11, 0xa5, 0x55, 0xfc, 0x9f, 0x9c, 0x87, 0x82, 0x0c, 0x4e, 0x44, 0x79, - 0x35, 0x1f, 0x88, 0xc0, 0xa4, 0x0c, 0x32, 0x0a, 0xe1, 0x81, 0x89, 0x21, 0x7f, 0x92, 0x1b, 0x10, - 0x85, 0x18, 0xe3, 0x62, 0x91, 0x1c, 0x53, 0x3e, 0x23, 0x42, 0x23, 0xf3, 0x90, 0x71, 0xf8, 0x17, - 0x51, 0x8a, 0x46, 0xc6, 0xb1, 0xc9, 0x2d, 0x28, 0x58, 0xb6, 0x4d, 0x6d, 0xd3, 0x0a, 0x27, 0xf8, - 0x24, 0x4d, 0x81, 0x71, 0xe3, 0x7b, 0x01, 0x52, 0x55, 0x43, 0x52, 0x85, 0x22, 0x7e, 0x91, 0xa4, - 0x17, 0x4c, 0xf4, 0x19, 0x93, 0x98, 0x43, 0x81, 0x91, 0x3d, 0x0c, 0xa8, 0x4d, 0x5e, 0x81, 0x1c, - 0x53, 0x0a, 0xb1, 0x93, 0x44, 0x2f, 0x89, 0x1e, 0xec, 0x6c, 0x73, 0x81, 0x6d, 0x9c, 0x30, 0x10, - 0x81, 0x7c, 0x1c, 0xb2, 0xbd, 0x95, 0x27, 0x62, 0x8f, 0x28, 0xc5, 0x2a, 0x11, 0xa1, 0xb1, 0xe6, - 0x5a, 0x01, 0xa6, 0x6d, 0x04, 0xe8, 0x17, 0x01, 0x62, 0x2e, 0xc3, 0x05, 0x6d, 0xfd, 0xab, 0x50, - 0x8c, 0xa8, 0xc9, 0xcb, 0xa0, 0x18, 0x10, 0x57, 0x76, 0xa3, 0xb8, 0x17, 0x99, 0xd1, 0x39, 0xc8, - 0x7b, 0x6c, 0x81, 0xe4, 0x6b, 0x3d, 0x83, 0xd9, 0x10, 0xd3, 0xd9, 0x32, 0xe4, 0x85, 0xce, 0xe0, - 0xf2, 0xcc, 0x19, 0xf2, 0xa7, 0xde, 0x85, 0x59, 0xd5, 0x21, 0xb1, 0x88, 0x55, 0xb9, 0x38, 0x9a, - 0xfe, 0xc2, 0x12, 0x3f, 0x3d, 0xcd, 0x0c, 0x9d, 0x9e, 0x5e, 0x85, 0x82, 0xdc, 0xc4, 0xd4, 0xf7, - 0xe0, 0x22, 0xde, 0x39, 0x30, 0xa2, 0x56, 0xfd, 0x15, 0xc8, 0x0b, 0x9f, 0x73, 0xf8, 0xa3, 0x60, - 0xfd, 0x77, 0x32, 0x70, 0xd2, 0xa0, 0x4c, 0x8b, 0xc4, 0x4b, 0xeb, 0x8f, 0xd8, 0x0b, 0xc2, 0xc4, - 0xdc, 0xc6, 0xc7, 0xd5, 0xfa, 0x4f, 0x34, 0x58, 0x18, 0x81, 0xfb, 0x41, 0x5e, 0x09, 0x90, 0x37, - 0xa1, 0xb8, 0xe6, 0x58, 0xed, 0xaa, 0x6d, 0xfb, 0x32, 0x8f, 0xc2, 0x60, 0xc5, 0x76, 0x58, 0xac, - 0xc2, 0xa0, 0xea, 0xee, 0x13, 0xa1, 0x92, 0x57, 0x85, 0x52, 0x64, 0x23, 0xb1, 0xca, 0x37, 0x8a, - 0xc0, 0xc7, 0x14, 0xbf, 0x50, 0xd4, 0xbf, 0x9f, 0x01, 0xc2, 0x81, 0x71, 0xb5, 0xf2, 0xd8, 0x2e, - 0xdd, 0xad, 0xc4, 0xd2, 0xc9, 0x27, 0xde, 0xe9, 0xe9, 0x4d, 0x94, 0x15, 0x7d, 0x2b, 0x03, 0x67, - 0x47, 0x13, 0x7e, 0xa0, 0xa5, 0xbc, 0x0e, 0x45, 0x7c, 0x1e, 0xa0, 0x3c, 0x03, 0xc5, 0xfd, 0x95, - 0xbf, 0x25, 0x40, 0xfc, 0x18, 0x81, 0x3c, 0x81, 0xb9, 0xbb, 0x56, 0x10, 0x6e, 0x50, 0xcb, 0x0f, - 0x1b, 0xd4, 0x0a, 0x27, 0x08, 0xb0, 0xa2, 0xef, 0x11, 0xa1, 0xe7, 0xdc, 0x95, 0x94, 0xe9, 0xef, - 0x11, 0x25, 0xd8, 0x46, 0x8a, 0x92, 0x9b, 0x40, 0x51, 0xde, 0x85, 0x93, 0x75, 0xda, 0xb1, 0xbc, - 0x5d, 0xd7, 0xa7, 0xe2, 0x30, 0x77, 0x09, 0xe6, 0x22, 0xd0, 0x48, 0x6d, 0x49, 0x36, 0x27, 0xf0, - 0x15, 0x41, 0xc4, 0xae, 0x24, 0xd9, 0xac, 0xff, 0x10, 0x8b, 0x4d, 0xef, 0xf6, 0x1c, 0x9f, 0x46, - 0x0d, 0xb2, 0xc0, 0xf9, 0x21, 0xf7, 0x4d, 0x96, 0xa1, 0x78, 0xcf, 0x7a, 0x86, 0xdf, 0xcc, 0x0b, - 0xc4, 0xf7, 0xf4, 0xf8, 0x4e, 0x6c, 0x3d, 0x33, 0xa3, 0xd2, 0x87, 0x11, 0xe3, 0xbc, 0xc8, 0xcf, - 0xea, 0xe9, 0x30, 0xbd, 0xe1, 0xb6, 0x6d, 0xea, 0x8b, 0xcb, 0xeb, 0x18, 0x5e, 0xed, 0x22, 0xc4, - 0x10, 0x2d, 0xfa, 0x7f, 0x68, 0x30, 0x1f, 0x8d, 0x18, 0x87, 0xf0, 0xa1, 0x8b, 0x24, 0xf5, 0x81, - 0xc1, 0xe2, 0x04, 0x1f, 0x18, 0x9c, 0xfa, 0xe5, 0x24, 0xa1, 0xff, 0x85, 0x06, 0xa7, 0x92, 0xb3, - 0x64, 0x3b, 0x91, 0x32, 0x10, 0x6d, 0xc2, 0x81, 0x64, 0x5e, 0xd8, 0x92, 0x64, 0xc7, 0x2e, 0xc9, - 0x37, 0x32, 0x30, 0x13, 0x0d, 0xf6, 0xd8, 0x1e, 0x5b, 0x7f, 0x36, 0xe1, 0x43, 0xcf, 0x46, 0x1f, - 0x7f, 0x11, 0xf3, 0x9a, 0xe8, 0xec, 0xba, 0xae, 0xf8, 0x0a, 0x71, 0x7e, 0xfd, 0x79, 0x98, 0x16, - 0xc6, 0xa4, 0x25, 0x3e, 0x88, 0x32, 0xb4, 0xba, 0xb5, 0x79, 0xc1, 0x7a, 0x1a, 0x17, 0x34, 0x30, - 0x04, 0x1d, 0x5e, 0x54, 0x7a, 0x4c, 0x1b, 0xe2, 0x4c, 0xec, 0xd8, 0xee, 0x51, 0xa3, 0x2f, 0x2a, - 0xc5, 0x13, 0x9b, 0x68, 0x77, 0xfa, 0x5e, 0x16, 0x4a, 0x69, 0x92, 0xa3, 0x2f, 0x7f, 0x6f, 0xf7, - 0x1a, 0x22, 0xb7, 0xc3, 0xe4, 0xcf, 0xeb, 0x35, 0x0c, 0x06, 0x23, 0x57, 0x20, 0xb7, 0xed, 0x3b, - 0xfb, 0x22, 0x99, 0xc3, 0x4b, 0x39, 0x9e, 0xef, 0xec, 0xab, 0x27, 0xf6, 0xac, 0x1d, 0x93, 0xaf, - 0xbb, 0x75, 0xe5, 0xa3, 0x5e, 0x3c, 0xf9, 0x6a, 0x07, 0xe9, 0xaf, 0x7a, 0x49, 0x34, 0xb6, 0x55, - 0xd6, 0xa8, 0xe5, 0x53, 0x9f, 0x3f, 0xa2, 0x9e, 0x8a, 0xb7, 0xca, 0x06, 0x82, 0xf9, 0xa3, 0x53, - 0x43, 0x45, 0x22, 0x6d, 0x20, 0xca, 0xcf, 0xc9, 0xbf, 0x6d, 0x29, 0x3f, 0xad, 0x75, 0x5a, 0x65, - 0x6d, 0xaa, 0xd6, 0x3c, 0x82, 0xef, 0x0b, 0x2c, 0x61, 0xe9, 0x3f, 0xc0, 0x10, 0xb8, 0xe3, 0x86, - 0x54, 0xec, 0xfc, 0xc7, 0xd6, 0x07, 0xc4, 0xd5, 0x41, 0xae, 0xa5, 0x17, 0xa2, 0x20, 0x58, 0x99, - 0x1d, 0xc7, 0x78, 0xf4, 0x7a, 0x6c, 0xb0, 0xbc, 0x4e, 0x28, 0xab, 0x83, 0x8a, 0xba, 0xfe, 0x99, - 0x06, 0x67, 0x46, 0xd2, 0x92, 0x25, 0x80, 0x38, 0xbe, 0x12, 0x52, 0xe2, 0x8f, 0x33, 0x23, 0xa8, - 0xa1, 0x60, 0x90, 0xaf, 0xa4, 0x23, 0xa3, 0xa3, 0x1d, 0xbb, 0xfc, 0x00, 0xc5, 0x7c, 0x32, 0x32, - 0x1a, 0x11, 0x0f, 0xe9, 0x3f, 0xc9, 0xc2, 0xa9, 0xa1, 0x2f, 0x2e, 0x1d, 0xf1, 0x35, 0xa4, 0xbd, - 0xd4, 0x77, 0x8b, 0x78, 0x25, 0xfb, 0xd5, 0x71, 0xdf, 0x7b, 0x1a, 0xf1, 0x15, 0x23, 0x2c, 0x7f, - 0x88, 0x47, 0xd8, 0x47, 0x7c, 0xcc, 0x28, 0x48, 0x7f, 0xcc, 0x88, 0x57, 0xb4, 0x3f, 0x39, 0xb6, - 0xb7, 0x17, 0xf0, 0x09, 0xba, 0xff, 0xbf, 0x5f, 0x15, 0x7a, 0xf5, 0x16, 0xcc, 0xaa, 0x77, 0x7a, - 0xf9, 0x47, 0x80, 0xef, 0xaf, 0x97, 0x4e, 0x90, 0x19, 0xc8, 0x6f, 0xaf, 0xdf, 0x5f, 0xdb, 0xbc, - 0x7f, 0xa7, 0xa4, 0x91, 0x59, 0x28, 0x54, 0xb7, 0xb7, 0x8d, 0x07, 0x8f, 0xd6, 0xd7, 0x4a, 0x19, - 0x02, 0x30, 0xbd, 0xb6, 0x7e, 0x7f, 0x73, 0x7d, 0xad, 0x94, 0xad, 0x95, 0xde, 0xfb, 0xf7, 0x8b, - 0x27, 0xde, 0xfb, 0xf9, 0x45, 0xed, 0x1f, 0x7e, 0x7e, 0x51, 0xfb, 0xb7, 0x9f, 0x5f, 0xd4, 0x1a, - 0xd3, 0xa8, 0x41, 0xaf, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x58, 0xf8, 0xae, 0x3e, - 0x5a, 0x00, 0x00, +var fileDescriptor_types_104b114ec6253b88 = []byte{ + // 6192 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x7c, 0x5d, 0x6c, 0x1c, 0xc9, + 0x71, 0xb0, 0x66, 0x77, 0xc9, 0xdd, 0x2d, 0xfe, 0x68, 0xd5, 0x14, 0xa5, 0x15, 0x4f, 0xa7, 0x95, + 0x47, 0xb6, 0x4e, 0x3a, 0xeb, 0x48, 0x8b, 0xe7, 0x3b, 0xfb, 0xce, 0xba, 0x4f, 0xde, 0x25, 0x29, + 0x91, 0x26, 0x25, 0xd2, 0xb3, 0x94, 0xf4, 0x39, 0xfe, 0x99, 0xcc, 0xee, 0xb4, 0x96, 0x13, 0xee, + 0xee, 0xcc, 0xcd, 0xcc, 0x52, 0xe4, 0x53, 0xe2, 0x00, 0x8e, 0x11, 0x18, 0xf1, 0x1f, 0x62, 0x38, + 0x06, 0x12, 0x24, 0x30, 0x10, 0xc4, 0x48, 0xe0, 0xa7, 0x3c, 0xe4, 0x29, 0x0f, 0x01, 0x0c, 0xe4, + 0x90, 0xa7, 0xbc, 0x05, 0x31, 0x92, 0x4d, 0xe2, 0xe4, 0x69, 0xfd, 0x9a, 0x97, 0x1c, 0x12, 0x20, + 0xe8, 0xea, 0xee, 0x99, 0x9e, 0xfd, 0x21, 0x57, 0x67, 0x1d, 0x10, 0xde, 0x13, 0xb9, 0xd5, 0x55, + 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0x55, 0xd5, 0xdd, 0x03, 0x53, 0xe1, 0x91, 0x47, 0x83, 0x45, 0xcf, + 0x77, 0x43, 0x97, 0x4c, 0xe0, 0x8f, 0x85, 0xf3, 0x0d, 0xb7, 0xe1, 0x22, 0x64, 0x89, 0xfd, 0xc7, + 0x1b, 0x17, 0x4a, 0x0d, 0xd7, 0x6d, 0x34, 0xe9, 0x12, 0xfe, 0xaa, 0x75, 0x9e, 0x2e, 0x85, 0x4e, + 0x8b, 0x06, 0xa1, 0xd5, 0xf2, 0x04, 0xc2, 0x4a, 0xc3, 0x09, 0xf7, 0x3a, 0xb5, 0xc5, 0xba, 0xdb, + 0x5a, 0x6a, 0xf8, 0xd6, 0x81, 0x13, 0x5a, 0xa1, 0xe3, 0xb6, 0xad, 0xe6, 0x52, 0x48, 0x9b, 0xd4, + 0x73, 0xfd, 0x70, 0xc9, 0xf2, 0x9c, 0x25, 0xec, 0x63, 0xe9, 0x99, 0x6f, 0x79, 0x1e, 0xf5, 0xe3, + 0x7f, 0x38, 0x13, 0xfd, 0xbf, 0x53, 0x90, 0xdf, 0xa4, 0xd4, 0x2b, 0x37, 0x9d, 0x03, 0x4a, 0xae, + 0x41, 0xe6, 0xa1, 0xd5, 0xa2, 0x45, 0xed, 0xaa, 0x76, 0x23, 0x5f, 0x39, 0xdb, 0xeb, 0x96, 0xa6, + 0x02, 0xea, 0x1f, 0x50, 0xdf, 0x6c, 0x5b, 0x2d, 0x6a, 0x60, 0x23, 0xf9, 0x24, 0xe4, 0xd9, 0xdf, + 0xc0, 0xb3, 0xea, 0xb4, 0x98, 0x42, 0xcc, 0x99, 0x5e, 0xb7, 0x94, 0x6f, 0x4b, 0xa0, 0x11, 0xb7, + 0x93, 0xeb, 0x90, 0xdd, 0xa2, 0x56, 0x40, 0x37, 0x56, 0x8b, 0xe9, 0xab, 0xda, 0x8d, 0x74, 0x65, + 0xba, 0xd7, 0x2d, 0xe5, 0x9a, 0x0c, 0x64, 0x3a, 0xb6, 0x21, 0x1b, 0xc9, 0x06, 0x64, 0xd7, 0x0e, + 0x3d, 0xc7, 0xa7, 0x41, 0x31, 0x73, 0x55, 0xbb, 0x31, 0xb5, 0xbc, 0xb0, 0xc8, 0xc7, 0xbf, 0x28, + 0xc7, 0xbf, 0xb8, 0x2b, 0xc7, 0x5f, 0x99, 0x7b, 0xaf, 0x5b, 0x3a, 0xd3, 0xeb, 0x96, 0xb2, 0x94, + 0x93, 0x7c, 0xf7, 0x5f, 0x4a, 0x9a, 0x21, 0xe9, 0xc9, 0x1d, 0xc8, 0xec, 0x1e, 0x79, 0xb4, 0x98, + 0xbf, 0xaa, 0xdd, 0x98, 0x5d, 0xbe, 0xb2, 0xc8, 0x35, 0x1e, 0x0d, 0x32, 0xfe, 0x8f, 0x61, 0x55, + 0x72, 0xbd, 0x6e, 0x29, 0xc3, 0x50, 0x0c, 0xa4, 0x22, 0xaf, 0xc1, 0xe4, 0xba, 0x1b, 0x84, 0x1b, + 0xab, 0x45, 0xc0, 0xa1, 0xcd, 0xf7, 0xba, 0xa5, 0x73, 0x7b, 0x6e, 0x10, 0x9a, 0x8e, 0x7d, 0xcb, + 0x6d, 0x39, 0x21, 0x6d, 0x79, 0xe1, 0x91, 0x21, 0x90, 0xf4, 0x77, 0x60, 0x26, 0xc1, 0x8f, 0x4c, + 0x41, 0xf6, 0xd1, 0xc3, 0xcd, 0x87, 0xdb, 0x4f, 0x1e, 0x16, 0xce, 0x90, 0x1c, 0x64, 0x1e, 0x6e, + 0xaf, 0xae, 0x15, 0x34, 0x92, 0x85, 0x74, 0x79, 0x67, 0xa7, 0x90, 0x22, 0xd3, 0x90, 0x5b, 0x2d, + 0xef, 0x96, 0x2b, 0xe5, 0xea, 0x5a, 0x21, 0xad, 0x7f, 0x33, 0x0d, 0xb9, 0x07, 0x34, 0xb4, 0x6c, + 0x2b, 0xb4, 0xc8, 0xe5, 0x84, 0xf6, 0x51, 0x30, 0x45, 0xed, 0xd7, 0x06, 0xd5, 0x3e, 0xd1, 0xeb, + 0x96, 0xb4, 0xd7, 0x54, 0x75, 0x7f, 0x0e, 0xa6, 0x56, 0x69, 0x50, 0xf7, 0x1d, 0x8f, 0x99, 0x02, + 0xaa, 0x3c, 0x5f, 0xb9, 0xd4, 0xeb, 0x96, 0xe6, 0xed, 0x18, 0xac, 0x0c, 0x43, 0xc5, 0x26, 0x1b, + 0x30, 0xb9, 0x65, 0xd5, 0x68, 0x33, 0x28, 0x4e, 0x5c, 0x4d, 0xdf, 0x98, 0x5a, 0x7e, 0x49, 0xa8, + 0x4e, 0x0a, 0xb8, 0xc8, 0x5b, 0xd7, 0xda, 0xa1, 0x7f, 0x54, 0x39, 0xdf, 0xeb, 0x96, 0x0a, 0x4d, + 0x04, 0xa8, 0x6a, 0xe1, 0x28, 0xa4, 0x1a, 0x4f, 0xe7, 0xe4, 0x89, 0xd3, 0xf9, 0xf2, 0x7b, 0xdd, + 0x92, 0xc6, 0xd4, 0x2c, 0xa6, 0x33, 0xe6, 0x97, 0x9c, 0xd8, 0xab, 0x90, 0xda, 0x58, 0x2d, 0x66, + 0xd1, 0x8c, 0x0a, 0xbd, 0x6e, 0x69, 0x3a, 0x31, 0x23, 0xa9, 0x8d, 0xd5, 0x85, 0xb7, 0x60, 0x4a, + 0x91, 0x91, 0x14, 0x20, 0xbd, 0x4f, 0x8f, 0xb8, 0x3e, 0x0d, 0xf6, 0x2f, 0x39, 0x0f, 0x13, 0x07, + 0x56, 0xb3, 0x23, 0x14, 0x68, 0xf0, 0x1f, 0x6f, 0xa7, 0x3e, 0xab, 0xe9, 0xdf, 0xcf, 0x40, 0xce, + 0x70, 0xf9, 0x12, 0x22, 0x37, 0x61, 0xa2, 0x1a, 0x5a, 0xa1, 0x9c, 0x8a, 0xb9, 0x5e, 0xb7, 0x74, + 0x36, 0x60, 0x00, 0xa5, 0x3f, 0x8e, 0xc1, 0x50, 0x77, 0xf6, 0xac, 0x40, 0x4e, 0x09, 0xa2, 0x7a, + 0x0c, 0xa0, 0xa2, 0x22, 0x06, 0xb9, 0x0e, 0x99, 0x07, 0xae, 0x4d, 0xc5, 0xac, 0x90, 0x5e, 0xb7, + 0x34, 0xdb, 0x72, 0x6d, 0x15, 0x11, 0xdb, 0xc9, 0x2d, 0xc8, 0xaf, 0x74, 0x7c, 0x9f, 0xb6, 0x99, + 0x15, 0x66, 0x10, 0x79, 0xb6, 0xd7, 0x2d, 0x41, 0x9d, 0x03, 0xd9, 0xba, 0x89, 0x11, 0x98, 0xaa, + 0xab, 0xa1, 0xe5, 0x87, 0xd4, 0x2e, 0x4e, 0x8c, 0xa5, 0x6a, 0xb6, 0x72, 0xce, 0x05, 0x9c, 0xa4, + 0x5f, 0xd5, 0x82, 0x13, 0x59, 0x87, 0xa9, 0xfb, 0xbe, 0x55, 0xa7, 0x3b, 0xd4, 0x77, 0x5c, 0x1b, + 0xe7, 0x30, 0x5d, 0xb9, 0xde, 0xeb, 0x96, 0x2e, 0x34, 0x18, 0xd8, 0xf4, 0x10, 0x1e, 0x53, 0xbf, + 0xdf, 0x2d, 0xe5, 0x56, 0x3b, 0x3e, 0x6a, 0xcf, 0x50, 0x49, 0xc9, 0xaf, 0xb3, 0x29, 0x09, 0x42, + 0x54, 0x2d, 0xb5, 0x71, 0xf6, 0x8e, 0x17, 0x51, 0x17, 0x22, 0x5e, 0x68, 0x5a, 0x41, 0x68, 0xfa, + 0x9c, 0xae, 0x4f, 0x4e, 0x95, 0x25, 0xd9, 0x86, 0x5c, 0xb5, 0xbe, 0x47, 0xed, 0x4e, 0x93, 0x16, + 0x73, 0xc8, 0xfe, 0xa2, 0x30, 0x5c, 0x39, 0x9f, 0xb2, 0xb9, 0xb2, 0x20, 0x78, 0x93, 0x40, 0x40, + 0x14, 0xdd, 0x47, 0x4c, 0xde, 0xce, 0xfd, 0xc1, 0x9f, 0x94, 0xce, 0xfc, 0xd6, 0x3f, 0x5d, 0x3d, + 0xa3, 0xff, 0x55, 0x0a, 0x0a, 0xfd, 0x4c, 0xc8, 0x53, 0x98, 0x79, 0xe4, 0xd9, 0x56, 0x48, 0x57, + 0x9a, 0x0e, 0x6d, 0x87, 0x01, 0x1a, 0xc9, 0xf1, 0x63, 0xfa, 0xb8, 0xe8, 0xb7, 0xd8, 0x41, 0x42, + 0xb3, 0xce, 0x29, 0xfb, 0x46, 0x95, 0x64, 0x1b, 0xf7, 0x53, 0x45, 0x17, 0x1c, 0xa0, 0x85, 0x3d, + 0x5f, 0x3f, 0xdc, 0x79, 0x8f, 0xe8, 0x47, 0xb0, 0x15, 0x06, 0xd4, 0xb6, 0x6b, 0x47, 0x68, 0x99, + 0xe3, 0x1b, 0x10, 0x23, 0x19, 0x62, 0x40, 0x0c, 0xac, 0xff, 0x87, 0x06, 0xb3, 0x06, 0x0d, 0xdc, + 0x8e, 0x5f, 0xa7, 0xeb, 0xd4, 0xb2, 0xa9, 0xcf, 0xcc, 0x7f, 0xd3, 0x69, 0xdb, 0x62, 0x4d, 0xa1, + 0xf9, 0xef, 0x3b, 0x6d, 0x75, 0x09, 0x63, 0x3b, 0xf9, 0x14, 0x64, 0xab, 0x9d, 0x1a, 0xa2, 0xf2, + 0x35, 0x75, 0x01, 0x67, 0xac, 0x53, 0x33, 0xfb, 0xd0, 0x25, 0x1a, 0x59, 0x82, 0xec, 0x63, 0xea, + 0x07, 0xb1, 0xc7, 0x43, 0xa7, 0x7d, 0xc0, 0x41, 0x2a, 0x81, 0xc0, 0x22, 0xf7, 0x63, 0xaf, 0x2b, + 0xb6, 0x9b, 0xb3, 0x7d, 0xbe, 0x2e, 0x36, 0x95, 0x96, 0x80, 0xa8, 0xa6, 0x22, 0xb1, 0xf4, 0xef, + 0xa5, 0xa0, 0xb0, 0x6a, 0x85, 0x56, 0xcd, 0x0a, 0x84, 0x3e, 0x1f, 0xbf, 0xce, 0xfc, 0xb8, 0x32, + 0x50, 0xf4, 0xe3, 0x4c, 0xf2, 0x0f, 0x3c, 0xbc, 0x4f, 0xf4, 0x0f, 0x6f, 0x8a, 0xed, 0x7d, 0x62, + 0x78, 0xf1, 0xa0, 0xde, 0x39, 0x79, 0x50, 0x05, 0x31, 0xa8, 0x9c, 0x1c, 0x54, 0x3c, 0x14, 0xf2, + 0x0e, 0x64, 0xaa, 0x1e, 0xad, 0x0b, 0x27, 0x22, 0x7d, 0x7f, 0x72, 0x70, 0x0c, 0xe1, 0xf1, 0xeb, + 0x95, 0x69, 0xc1, 0x26, 0x13, 0x78, 0xb4, 0x6e, 0x20, 0x99, 0xb2, 0x68, 0x7e, 0x7b, 0x02, 0xce, + 0x0f, 0x23, 0xeb, 0xdf, 0x9c, 0xb4, 0xe7, 0xda, 0x9c, 0x6e, 0x40, 0x6e, 0x87, 0x99, 0x63, 0xdd, + 0x6d, 0x0a, 0xbd, 0x61, 0x24, 0xe1, 0x09, 0x98, 0x11, 0xb5, 0x92, 0x4b, 0x90, 0x7e, 0x64, 0x6c, + 0x08, 0x55, 0x65, 0x7b, 0xdd, 0x52, 0xba, 0xe3, 0x3b, 0x06, 0x83, 0xb1, 0xcd, 0x7d, 0xa5, 0xbc, + 0x42, 0xfd, 0x10, 0x15, 0x34, 0xcd, 0xed, 0xa4, 0x6e, 0x99, 0x75, 0xea, 0x87, 0xea, 0x2e, 0xc6, + 0x91, 0xc8, 0x4d, 0x48, 0x97, 0x9f, 0x54, 0x85, 0x46, 0x40, 0x68, 0xa4, 0xfc, 0xa4, 0x5a, 0x99, + 0x12, 0x0a, 0x48, 0x5b, 0xcf, 0x02, 0x83, 0xe1, 0xa8, 0x73, 0x34, 0x79, 0xcc, 0x1c, 0xdd, 0x80, + 0x1c, 0x0b, 0x1c, 0xd8, 0xb6, 0x8e, 0xae, 0x50, 0x8c, 0x62, 0x4f, 0xc0, 0x8c, 0xa8, 0x95, 0x5c, + 0x8b, 0xe2, 0x90, 0x5c, 0xcc, 0x4f, 0xc4, 0x21, 0x32, 0xfa, 0x20, 0x07, 0x30, 0xb3, 0x7a, 0xd4, + 0xb6, 0x5a, 0x4e, 0x5d, 0x6c, 0xdc, 0x79, 0xdc, 0xb8, 0x17, 0x8f, 0x99, 0xbc, 0xc5, 0x04, 0x01, + 0xdf, 0xcb, 0xaf, 0x4a, 0xb7, 0x61, 0xf3, 0x36, 0x73, 0x60, 0x5f, 0x4f, 0x76, 0xc3, 0xd6, 0x8f, + 0x74, 0x8b, 0x18, 0x26, 0xc5, 0xa6, 0x26, 0xc1, 0xf1, 0xfa, 0xf1, 0x05, 0x44, 0x5d, 0x3f, 0x12, + 0x6b, 0xe1, 0x09, 0x90, 0x41, 0x79, 0x86, 0xec, 0xdb, 0x9f, 0x54, 0xf7, 0xed, 0xa9, 0xe5, 0x79, + 0xd1, 0xdb, 0x8a, 0xdb, 0x6a, 0x59, 0x6d, 0x1b, 0x69, 0x1f, 0x2f, 0xab, 0xdb, 0xf9, 0xeb, 0x38, + 0x75, 0xe4, 0x16, 0x4c, 0x1a, 0xb4, 0x11, 0x5b, 0x1b, 0x46, 0x2d, 0x3e, 0x42, 0xd4, 0xf9, 0xe6, + 0x38, 0xfa, 0xd7, 0x53, 0x90, 0x13, 0xab, 0x78, 0xf9, 0x94, 0xae, 0xe2, 0x37, 0x12, 0xab, 0x78, + 0x4e, 0x90, 0x2a, 0x06, 0xb0, 0x7c, 0xc2, 0xea, 0xfd, 0xce, 0x04, 0x4c, 0xab, 0xe8, 0x4c, 0x0f, + 0x65, 0xdb, 0xf6, 0x55, 0x3d, 0x58, 0xb6, 0xed, 0x1b, 0x08, 0x25, 0x6f, 0x01, 0xec, 0x74, 0x6a, + 0x4d, 0xa7, 0x8e, 0x38, 0xa9, 0x78, 0x49, 0x7b, 0x08, 0x35, 0x19, 0xaa, 0xa2, 0x0d, 0x05, 0x39, + 0xb1, 0x16, 0xd2, 0xc7, 0xae, 0x85, 0xaf, 0x41, 0x7e, 0xa5, 0x65, 0x0b, 0x13, 0xcf, 0xa0, 0x89, + 0xeb, 0x43, 0x46, 0xb6, 0x18, 0x21, 0x71, 0xb3, 0xbe, 0x2c, 0x06, 0x7a, 0xbe, 0xde, 0xb2, 0x07, + 0x4d, 0x3a, 0x66, 0x99, 0x30, 0xe7, 0x89, 0x5f, 0xc1, 0x9c, 0xc9, 0x9b, 0x90, 0x7f, 0x14, 0xd0, + 0xdd, 0x4e, 0xbb, 0x4d, 0x9b, 0xe8, 0x07, 0x72, 0x95, 0x22, 0x13, 0xa0, 0x13, 0x50, 0x33, 0x44, + 0xa8, 0x2a, 0x40, 0x84, 0xaa, 0xda, 0x46, 0xf6, 0x18, 0xdb, 0x58, 0x86, 0x4c, 0xd9, 0xf3, 0xe4, + 0x2a, 0x8f, 0x1c, 0x92, 0xe7, 0xf1, 0xdd, 0xd4, 0xf2, 0x3c, 0x75, 0x80, 0x88, 0x4b, 0x28, 0x90, + 0xcd, 0x4e, 0x8d, 0xfa, 0x6d, 0x1a, 0xd2, 0x60, 0xa5, 0xd9, 0x09, 0x42, 0x16, 0x4a, 0x00, 0x72, + 0x28, 0xca, 0xdc, 0xa8, 0x1f, 0xa1, 0xf2, 0x52, 0xaf, 0x5b, 0xba, 0xb8, 0xdf, 0xa9, 0xb1, 0x50, + 0x85, 0x93, 0x28, 0x8c, 0x87, 0x30, 0x5c, 0xa8, 0xc2, 0x6c, 0x52, 0xfb, 0x2f, 0x60, 0x11, 0x7f, + 0x21, 0x93, 0xcb, 0x15, 0xf2, 0xfa, 0x3f, 0x64, 0x20, 0x5d, 0xf6, 0xbc, 0x13, 0xd2, 0x23, 0xe1, + 0xf5, 0x53, 0x43, 0xbc, 0x7e, 0xd2, 0x46, 0xd3, 0xcf, 0x63, 0xa3, 0x8f, 0x61, 0x9a, 0x85, 0xf9, + 0x91, 0x7f, 0xe5, 0xc6, 0x77, 0x39, 0xd6, 0xfc, 0xa2, 0xda, 0x7c, 0x5c, 0x66, 0x94, 0xe0, 0x43, + 0xcc, 0x7e, 0xc7, 0xcd, 0x33, 0xae, 0x97, 0x15, 0xc6, 0x43, 0xfc, 0x74, 0x64, 0x84, 0x75, 0xae, + 0xb2, 0x63, 0x3c, 0xf4, 0x3a, 0x90, 0x8d, 0x76, 0x40, 0xeb, 0x1d, 0x9f, 0x56, 0xf7, 0x1d, 0xef, + 0x31, 0xf5, 0x9d, 0xa7, 0x47, 0xaa, 0x49, 0x3a, 0xa2, 0xd5, 0x0c, 0xf6, 0x1d, 0xcf, 0x3c, 0xc0, + 0x76, 0x63, 0x08, 0x0d, 0xb9, 0x0b, 0x59, 0x83, 0x3e, 0xf3, 0x9d, 0x90, 0x8a, 0xe0, 0x7d, 0x56, + 0xae, 0x0d, 0x0e, 0xe5, 0x9b, 0xa8, 0xcf, 0x7f, 0xa8, 0x8e, 0x4f, 0xb4, 0x2f, 0xdc, 0x85, 0x73, + 0x03, 0x4a, 0x7a, 0x9e, 0xd4, 0xec, 0xc3, 0xdc, 0x24, 0xa4, 0x90, 0xcc, 0x19, 0x19, 0xd4, 0x76, + 0x7c, 0x5a, 0x0f, 0x8b, 0xda, 0xd5, 0xb4, 0x74, 0x46, 0xbe, 0x80, 0x19, 0x51, 0xab, 0xfe, 0x2d, + 0x0d, 0x66, 0x93, 0x2c, 0xc9, 0x22, 0x4c, 0x8a, 0x44, 0x49, 0xc3, 0x44, 0x89, 0xed, 0x05, 0x93, + 0x3c, 0x45, 0x4a, 0x24, 0x46, 0x02, 0x8b, 0x2d, 0x77, 0xc1, 0xa1, 0x98, 0xc2, 0xbe, 0x70, 0xb9, + 0x8b, 0x49, 0x35, 0x64, 0x1b, 0xd1, 0xd9, 0xe6, 0x15, 0x74, 0x9a, 0xa1, 0xb0, 0x59, 0x60, 0x6c, + 0x7d, 0x84, 0x18, 0xa2, 0x45, 0xff, 0x12, 0xc0, 0xee, 0x56, 0x75, 0x93, 0x1e, 0xed, 0x58, 0x0e, + 0x86, 0xd8, 0x18, 0xdd, 0x68, 0x18, 0xdd, 0xa0, 0x53, 0xe8, 0x0b, 0x6d, 0xb0, 0x9d, 0x5c, 0x83, + 0xf4, 0x26, 0x3d, 0x42, 0x3d, 0x4d, 0x57, 0xce, 0xf5, 0xba, 0xa5, 0x99, 0x7d, 0xaa, 0x84, 0xf2, + 0x06, 0x6b, 0xd5, 0x7f, 0x13, 0xe0, 0x0b, 0x4f, 0x76, 0x25, 0xeb, 0x37, 0x21, 0xcf, 0xd7, 0xc5, + 0xa6, 0x50, 0xfa, 0x34, 0xb7, 0x23, 0xb1, 0x86, 0x92, 0xf4, 0x31, 0x2a, 0x2e, 0x3e, 0xdf, 0x39, + 0xb0, 0x42, 0x1a, 0xf7, 0xc8, 0x17, 0x1f, 0x87, 0xf6, 0x51, 0x2a, 0xc8, 0xfa, 0x77, 0x52, 0x70, + 0x96, 0x89, 0x5b, 0xee, 0x84, 0x7b, 0xae, 0xef, 0x84, 0x47, 0xa7, 0x76, 0x57, 0xbe, 0x93, 0xd8, + 0x95, 0x17, 0xa4, 0x61, 0xaa, 0x63, 0x1b, 0x6b, 0x73, 0xfe, 0xe1, 0x24, 0xcc, 0x0d, 0xa1, 0x22, + 0xb7, 0x44, 0xc9, 0x8b, 0x6b, 0xa5, 0x28, 0x4b, 0x5a, 0xef, 0x77, 0x4b, 0xd3, 0x12, 0x7d, 0x37, + 0x2e, 0x71, 0x2d, 0xc3, 0x94, 0xf0, 0xdb, 0xe8, 0x4f, 0xb9, 0xa6, 0xb0, 0xa0, 0x22, 0x9c, 0x3d, + 0xaf, 0xf6, 0xa9, 0x48, 0xe4, 0x2e, 0x4c, 0xaf, 0xec, 0xd1, 0xfa, 0xbe, 0xd3, 0x6e, 0x6c, 0xd2, + 0xa3, 0xa0, 0x98, 0xbe, 0x9a, 0xbe, 0x31, 0xcd, 0xb7, 0x89, 0xba, 0x80, 0xb3, 0x99, 0x4c, 0x78, + 0x3c, 0x95, 0x80, 0xdc, 0x81, 0xa9, 0xaa, 0xd3, 0x68, 0x4b, 0xfa, 0x0c, 0xd2, 0x2f, 0xb0, 0x3c, + 0x3f, 0xe0, 0xe0, 0x7e, 0x72, 0x15, 0x9d, 0xdc, 0x84, 0x09, 0xc3, 0x6d, 0x52, 0xee, 0x27, 0x45, + 0x95, 0xc5, 0x67, 0x00, 0xb5, 0xca, 0x82, 0x18, 0x64, 0x1d, 0xb2, 0xec, 0x9f, 0x07, 0x96, 0x57, + 0x9c, 0x44, 0xa7, 0x4a, 0xa2, 0xbd, 0x1c, 0xa1, 0x9e, 0xd3, 0x6e, 0xa8, 0xdb, 0x79, 0x93, 0x9a, + 0x2d, 0xcb, 0x4b, 0x38, 0x2e, 0x8e, 0x48, 0x76, 0x61, 0x2a, 0x5e, 0x5b, 0x41, 0x31, 0x8b, 0xdc, + 0xce, 0x09, 0x6e, 0x71, 0x4b, 0xa5, 0x24, 0x98, 0x5d, 0x0c, 0x9b, 0x01, 0x1b, 0x85, 0xe9, 0x31, + 0x7c, 0x75, 0x28, 0x0a, 0x9b, 0x44, 0xb0, 0x91, 0x1b, 0x1d, 0x6c, 0x68, 0x27, 0x06, 0x1b, 0x36, + 0x80, 0x50, 0x51, 0xb9, 0xd9, 0x10, 0xd5, 0xce, 0x9b, 0xa3, 0x4d, 0x6b, 0x31, 0x46, 0xc6, 0xc2, + 0x27, 0x2e, 0x42, 0xa9, 0x7b, 0xab, 0xd9, 0x50, 0x17, 0x61, 0x8c, 0xca, 0x94, 0x10, 0x7b, 0x01, + 0x19, 0x38, 0x48, 0x25, 0xc4, 0x2d, 0xb1, 0x12, 0x7e, 0xe3, 0x59, 0x38, 0x5c, 0x09, 0x0a, 0x1b, + 0x7d, 0x1b, 0x66, 0x93, 0xe2, 0x24, 0xeb, 0xa6, 0xd3, 0x90, 0x33, 0xaa, 0x65, 0xb3, 0xba, 0x5e, + 0xbe, 0x5d, 0xd0, 0x48, 0x01, 0xa6, 0xc5, 0xaf, 0x65, 0x73, 0xf9, 0x8d, 0x37, 0x0b, 0xa9, 0x04, + 0xe4, 0x8d, 0xdb, 0xcb, 0x85, 0xb4, 0x6e, 0xc0, 0x94, 0x32, 0xbf, 0xdc, 0x75, 0xb6, 0xdc, 0xa8, + 0x82, 0x27, 0x5c, 0x27, 0x83, 0x18, 0xa2, 0x85, 0x94, 0x60, 0x62, 0xcb, 0xad, 0x5b, 0x4d, 0xe1, + 0x83, 0xf3, 0xbd, 0x6e, 0x69, 0xa2, 0xc9, 0x00, 0x06, 0x87, 0xeb, 0x7f, 0xa3, 0x41, 0x61, 0xc7, + 0x77, 0x0f, 0x1c, 0xe6, 0x02, 0x76, 0xdd, 0x7d, 0xda, 0x7e, 0x7c, 0x9b, 0xbc, 0x26, 0x2d, 0x91, + 0xef, 0x12, 0x17, 0x19, 0x15, 0x5a, 0xe2, 0xfb, 0xdd, 0x12, 0x54, 0x8f, 0x82, 0x90, 0xb6, 0x58, + 0xbb, 0xb4, 0x46, 0xa5, 0x10, 0x9a, 0x1a, 0xbf, 0xb8, 0x72, 0x42, 0x21, 0xb4, 0x04, 0x13, 0x28, + 0x8e, 0x70, 0x59, 0x28, 0x79, 0xc8, 0x00, 0x06, 0x87, 0x2b, 0x1e, 0xe3, 0x7b, 0xa9, 0x81, 0x31, + 0x2c, 0x7f, 0xa4, 0x0a, 0x14, 0xc9, 0xc1, 0x8d, 0xe5, 0x45, 0xd7, 0xe0, 0xfc, 0x30, 0xaa, 0xe7, + 0x9c, 0x5a, 0xfd, 0xf7, 0x52, 0x30, 0xcb, 0x03, 0x1b, 0x64, 0x12, 0x9c, 0x5a, 0xc5, 0x7e, 0x2e, + 0xa1, 0xd8, 0x4b, 0x32, 0xb3, 0x52, 0x86, 0x36, 0x96, 0x5a, 0xf7, 0x80, 0x0c, 0xd2, 0x10, 0x43, + 0x46, 0xd0, 0x1c, 0x8a, 0xba, 0x8d, 0x2b, 0xb4, 0xfd, 0xcb, 0xab, 0x32, 0x2f, 0xba, 0x98, 0x09, + 0x90, 0xc8, 0x44, 0xb3, 0x0e, 0x8c, 0x04, 0x0f, 0xfd, 0x5b, 0x29, 0x98, 0x51, 0x36, 0xa7, 0x53, + 0xab, 0xf8, 0xb7, 0x13, 0x8a, 0x97, 0xd9, 0x98, 0x32, 0xb2, 0xb1, 0xf4, 0x7e, 0x1f, 0xce, 0x0d, + 0x90, 0xf4, 0xef, 0xf1, 0xda, 0x18, 0x7b, 0x3c, 0x8f, 0xb7, 0xf8, 0xef, 0x15, 0xb7, 0xfd, 0xd4, + 0x69, 0x9c, 0xda, 0x5a, 0xe6, 0x88, 0x78, 0x4b, 0x1d, 0xdb, 0x58, 0xa5, 0xcc, 0x5f, 0x4e, 0xc0, + 0xdc, 0x10, 0x2a, 0x52, 0x86, 0x42, 0x95, 0x06, 0x28, 0x32, 0xad, 0xbb, 0xbe, 0xed, 0xb4, 0x1b, + 0x42, 0x43, 0x98, 0x0c, 0x05, 0xbc, 0xcd, 0xf4, 0x65, 0xa3, 0x31, 0x80, 0x8e, 0x87, 0x3c, 0x9c, + 0xf3, 0xc6, 0xaa, 0x50, 0x1e, 0x3f, 0xe4, 0x11, 0xd3, 0x83, 0x87, 0x3c, 0x12, 0x81, 0x6c, 0xc1, + 0xdc, 0x8e, 0xef, 0x1e, 0x1e, 0x61, 0x48, 0x15, 0xac, 0xbb, 0x41, 0x28, 0xa2, 0x30, 0x46, 0x87, + 0x51, 0x94, 0xc7, 0x9a, 0x4d, 0x8c, 0xc5, 0x02, 0x13, 0xeb, 0x84, 0x2c, 0x9e, 0x32, 0x86, 0x91, + 0x91, 0xcf, 0xc0, 0x44, 0xb9, 0x63, 0x3b, 0xa1, 0x50, 0xad, 0x0c, 0x90, 0x10, 0xc6, 0xc7, 0x59, + 0x99, 0x11, 0x7a, 0x99, 0xb0, 0x18, 0xd0, 0xe0, 0xf8, 0xe4, 0x8b, 0xcc, 0xd4, 0x1c, 0xda, 0x0e, + 0x37, 0xec, 0x26, 0x65, 0xfb, 0x96, 0xdb, 0x09, 0x51, 0xc9, 0xe9, 0xca, 0xb5, 0x5e, 0xb7, 0x34, + 0xc7, 0xcf, 0x35, 0x4c, 0xc7, 0x6e, 0x52, 0x33, 0xe4, 0xcd, 0x89, 0x04, 0x68, 0x90, 0x9a, 0x7c, + 0x09, 0xe6, 0x57, 0x9d, 0xa0, 0xee, 0xb6, 0xdb, 0xb4, 0x1e, 0xf2, 0x0d, 0xce, 0xc6, 0x1c, 0x86, + 0xe7, 0xaa, 0x8c, 0xed, 0x45, 0x3b, 0x42, 0x30, 0xf9, 0xce, 0x68, 0x63, 0xc5, 0xf6, 0xfd, 0x6e, + 0x29, 0x53, 0x71, 0xdd, 0xa6, 0x31, 0x9c, 0x03, 0x93, 0x36, 0x3a, 0x9b, 0xdd, 0x68, 0x87, 0xd4, + 0x3f, 0xb0, 0x9a, 0xe2, 0xf8, 0x10, 0xa5, 0xdd, 0xa7, 0xd4, 0x33, 0x2d, 0xd6, 0x6a, 0x3a, 0xa2, + 0x39, 0x29, 0xed, 0x00, 0x35, 0xb9, 0xa7, 0xb0, 0x5c, 0x71, 0x3b, 0xed, 0xf0, 0x81, 0x75, 0x88, + 0x51, 0x5c, 0x9a, 0x67, 0x43, 0x0a, 0xcb, 0x3a, 0x6b, 0x36, 0x5b, 0xd6, 0xa1, 0x31, 0x48, 0x42, + 0x3e, 0x0d, 0x79, 0x8c, 0x31, 0x58, 0x8c, 0x86, 0xa1, 0x5b, 0x0e, 0x97, 0x0e, 0x60, 0xfc, 0x61, + 0x5a, 0x9d, 0x70, 0x2f, 0x1a, 0x5c, 0x8c, 0x48, 0xbe, 0x0a, 0xf3, 0xc2, 0x8e, 0x56, 0xdc, 0x76, + 0xe8, 0xbb, 0x4d, 0x39, 0x05, 0x80, 0x12, 0xbc, 0xc2, 0x74, 0x25, 0x6d, 0xaf, 0xce, 0x31, 0x86, + 0x4e, 0xc3, 0x70, 0x2e, 0xfa, 0x77, 0x72, 0x30, 0xa5, 0xd8, 0x00, 0xcb, 0x26, 0x95, 0xac, 0x02, + 0xb3, 0x49, 0x66, 0x28, 0x6a, 0x36, 0x89, 0xa1, 0x5b, 0x5c, 0x64, 0x4d, 0x9d, 0x5c, 0x64, 0x25, + 0x5b, 0x50, 0xc0, 0x4e, 0x84, 0x0c, 0x41, 0x5c, 0xab, 0xbf, 0xda, 0xeb, 0x96, 0x2e, 0xa3, 0xbd, + 0x99, 0x62, 0x14, 0x81, 0xd9, 0xf1, 0x1d, 0x85, 0xc7, 0x00, 0x25, 0xf9, 0xb1, 0x06, 0xb3, 0x08, + 0x5c, 0x3b, 0xa0, 0xed, 0x10, 0x99, 0x71, 0xa3, 0xbe, 0xb0, 0x18, 0xdd, 0x74, 0xa8, 0x86, 0xbe, + 0xd3, 0x6e, 0x3c, 0x66, 0x69, 0x7f, 0x50, 0xa9, 0x31, 0xc3, 0xfe, 0x79, 0xb7, 0x74, 0xe7, 0x83, + 0xdc, 0x9e, 0x10, 0xac, 0x82, 0x5e, 0xb7, 0xb4, 0xc0, 0x05, 0xa5, 0xd8, 0x6d, 0x9f, 0x98, 0x7d, + 0x12, 0x91, 0x7b, 0x42, 0xc6, 0x5d, 0xab, 0xd6, 0xa4, 0xe8, 0x8f, 0x27, 0x70, 0xc0, 0x57, 0x62, + 0x3e, 0x21, 0x6b, 0x42, 0x9f, 0x3c, 0xc0, 0x27, 0xa2, 0x22, 0xbf, 0x06, 0x17, 0xd7, 0xda, 0xec, + 0x17, 0x9b, 0x38, 0xa7, 0xdd, 0x71, 0x3b, 0x41, 0xc5, 0xaa, 0xef, 0x77, 0xbc, 0x40, 0xac, 0x16, + 0xd4, 0x60, 0x3d, 0x6a, 0x34, 0x6b, 0xbc, 0x55, 0x61, 0x39, 0x8a, 0x01, 0x59, 0x87, 0x73, 0xbc, + 0xa9, 0xdc, 0x09, 0xdd, 0x6a, 0xdd, 0x6a, 0x32, 0x9f, 0x96, 0x45, 0xae, 0xe8, 0x5f, 0xac, 0x4e, + 0xe8, 0x9a, 0x01, 0x87, 0x2b, 0xfc, 0x06, 0x89, 0xc8, 0x06, 0x9c, 0x35, 0xa8, 0x65, 0x3f, 0xb0, + 0x0e, 0x57, 0x2c, 0xcf, 0xaa, 0x3b, 0xe1, 0x91, 0x58, 0x21, 0xa5, 0x5e, 0xb7, 0xf4, 0x92, 0x4f, + 0x2d, 0x9b, 0xad, 0x0a, 0xb3, 0x2e, 0x1a, 0x15, 0x66, 0xfd, 0x74, 0x11, 0x2b, 0xa7, 0x1d, 0xb1, + 0xca, 0xf7, 0xb3, 0x72, 0xda, 0xa3, 0x59, 0xc5, 0x74, 0x92, 0xd5, 0xae, 0xe5, 0x37, 0x68, 0x88, + 0xb6, 0x80, 0xab, 0x46, 0x53, 0x58, 0x85, 0xd8, 0x66, 0x62, 0x7d, 0xa8, 0x9f, 0x95, 0x42, 0xc7, + 0x2c, 0xf8, 0x89, 0xef, 0x84, 0x54, 0x1d, 0xe1, 0x14, 0x8a, 0x85, 0xfa, 0xc7, 0x82, 0xd2, 0xa8, + 0x21, 0x0e, 0x50, 0xc6, 0xdc, 0x94, 0x41, 0x4e, 0x0f, 0x70, 0x1b, 0x3e, 0xca, 0x01, 0xca, 0x88, + 0x9b, 0x3a, 0xce, 0x19, 0x1c, 0xa7, 0xc2, 0x6d, 0xc4, 0x40, 0x07, 0x28, 0xf5, 0xff, 0xd2, 0x94, + 0x4b, 0x27, 0xa7, 0x34, 0x16, 0x78, 0x33, 0x11, 0x0b, 0x9c, 0x17, 0xa4, 0xd1, 0xa8, 0x58, 0xdb, + 0xb0, 0x28, 0x40, 0x3f, 0x0b, 0x33, 0x09, 0x24, 0xfd, 0x47, 0x29, 0x38, 0x6f, 0xd0, 0x80, 0x86, + 0x3b, 0x56, 0x10, 0x3c, 0x73, 0x7d, 0x9b, 0xc7, 0xac, 0xa7, 0x35, 0x46, 0x2a, 0x27, 0xf4, 0x52, + 0x8a, 0x8a, 0xba, 0xfd, 0x03, 0x1c, 0x2b, 0x50, 0xfa, 0x89, 0x06, 0xc5, 0x51, 0xa4, 0x4c, 0x3f, + 0x8f, 0x02, 0x9a, 0x38, 0x41, 0xea, 0x04, 0xd4, 0x37, 0x10, 0xca, 0x0b, 0xf7, 0x5b, 0xc9, 0xc2, + 0x7d, 0xd3, 0x60, 0x30, 0x96, 0x3c, 0xaf, 0xf8, 0x14, 0xef, 0x8d, 0x64, 0xc6, 0x4f, 0x9e, 0xeb, + 0x9c, 0xa4, 0x3f, 0x79, 0x16, 0x9c, 0xf4, 0x3f, 0x4b, 0xc1, 0x4b, 0x43, 0x44, 0xa5, 0x75, 0x9f, + 0x86, 0xc1, 0xa9, 0x9d, 0xcd, 0xf5, 0xc4, 0x6c, 0x5e, 0x1f, 0x3d, 0x9b, 0x7c, 0x9c, 0x63, 0x4d, + 0xea, 0xdf, 0x69, 0x50, 0x3a, 0x81, 0x03, 0xb9, 0x06, 0x93, 0xdb, 0xbb, 0x3b, 0xb2, 0x26, 0x2c, + 0x06, 0xe7, 0x7a, 0x18, 0x7d, 0x1a, 0xa2, 0x89, 0xbc, 0x06, 0x93, 0x5f, 0x34, 0x56, 0x5c, 0x5b, + 0xd6, 0x1a, 0x31, 0x48, 0x7e, 0xd7, 0x37, 0xeb, 0xc9, 0xdb, 0x4f, 0x02, 0x49, 0x9d, 0xf6, 0xf4, + 0x0b, 0x9b, 0x76, 0x96, 0xdc, 0x94, 0xeb, 0x75, 0x1a, 0x04, 0x06, 0x7d, 0xb7, 0x43, 0x83, 0xf0, + 0x23, 0x96, 0xdc, 0x24, 0xc6, 0x36, 0xd6, 0xf4, 0xfe, 0xf1, 0x24, 0xcc, 0x0d, 0xa1, 0x3a, 0x61, + 0xb9, 0x96, 0x64, 0x91, 0x44, 0xa9, 0x9a, 0x61, 0x91, 0x44, 0x56, 0xbc, 0xfe, 0x9f, 0xbc, 0x3b, + 0x97, 0xc6, 0x8a, 0xe4, 0x5c, 0x64, 0x8a, 0xbc, 0x0f, 0xd6, 0x74, 0xec, 0x85, 0xba, 0x0f, 0x63, + 0xd1, 0xab, 0x65, 0xb8, 0x89, 0x17, 0x56, 0x86, 0xab, 0xc0, 0x8c, 0x18, 0x95, 0x41, 0xad, 0x20, + 0xba, 0xf9, 0x71, 0xb9, 0xd7, 0x2d, 0x15, 0x7d, 0xde, 0x60, 0xfa, 0xd8, 0xa2, 0x9e, 0xd3, 0x25, + 0x48, 0x38, 0x8f, 0xc0, 0x6d, 0x1e, 0x50, 0xc1, 0x23, 0xab, 0xf2, 0xc0, 0x86, 0xa1, 0x3c, 0x14, + 0x12, 0xf2, 0x17, 0x1a, 0x10, 0x01, 0x29, 0xb7, 0xdb, 0xa2, 0x3c, 0x1c, 0x88, 0xe2, 0xf2, 0x7c, + 0x1c, 0x07, 0xf3, 0xe3, 0x2a, 0x1e, 0x06, 0xdb, 0x22, 0x0c, 0xfe, 0xdc, 0x07, 0x0a, 0x83, 0x77, + 0x7d, 0xcb, 0x09, 0x59, 0x14, 0xfc, 0xb2, 0x94, 0xd1, 0x8a, 0x3b, 0x56, 0x4f, 0x8a, 0x07, 0xc5, + 0x22, 0x3f, 0xd1, 0xe0, 0x1c, 0x2f, 0xa6, 0xa9, 0xc2, 0xe6, 0x8f, 0x13, 0xb6, 0xfe, 0x62, 0x84, + 0xbd, 0x1c, 0x60, 0xb7, 0x23, 0x64, 0x1d, 0x14, 0x4a, 0xff, 0xba, 0xd6, 0xb7, 0x42, 0xee, 0x39, + 0xcd, 0x90, 0xfa, 0xe4, 0x02, 0x5e, 0x44, 0xe5, 0xeb, 0x63, 0xb2, 0xd7, 0x2d, 0xa5, 0x1c, 0xdb, + 0x48, 0x6d, 0xac, 0x46, 0x2b, 0x27, 0x35, 0x74, 0xe5, 0x7c, 0x7a, 0x8c, 0x85, 0x81, 0xcb, 0x09, + 0x17, 0x86, 0x58, 0x0e, 0xba, 0x05, 0x84, 0x8b, 0xc0, 0x42, 0xbc, 0x9a, 0xd3, 0x74, 0x42, 0x87, + 0x06, 0x64, 0x13, 0x0a, 0x82, 0x8e, 0x45, 0xdf, 0x6a, 0xd5, 0x52, 0x84, 0xb3, 0x51, 0x9b, 0xd9, + 0x7f, 0x4c, 0x32, 0x40, 0xa8, 0x7f, 0x57, 0x83, 0x4b, 0x83, 0x7d, 0x08, 0x34, 0x96, 0x05, 0x2a, + 0xee, 0x00, 0xb3, 0x40, 0x36, 0x28, 0x35, 0x0b, 0xc4, 0xe1, 0x0d, 0x13, 0x29, 0x85, 0xf9, 0xc3, + 0x07, 0x10, 0xe9, 0x77, 0x53, 0x30, 0xbd, 0xd3, 0xec, 0x34, 0x9c, 0xf6, 0xaa, 0x15, 0x5a, 0xa7, + 0xd6, 0x55, 0xbf, 0x95, 0x70, 0xd5, 0x51, 0xd1, 0x33, 0x1a, 0xd8, 0x58, 0x7e, 0xfa, 0xf7, 0x35, + 0x38, 0x1b, 0x93, 0xf0, 0xc3, 0xef, 0x75, 0xc8, 0xb0, 0x1f, 0xa2, 0x9a, 0x7a, 0x75, 0x80, 0x31, + 0x62, 0x2d, 0x46, 0xff, 0xf1, 0x69, 0xeb, 0xbb, 0xc5, 0x88, 0x1c, 0x16, 0x3e, 0x03, 0xf9, 0x98, + 0xed, 0xf3, 0x5c, 0x98, 0xfe, 0x4b, 0x0d, 0x0a, 0xfd, 0x23, 0x21, 0x9b, 0x90, 0x65, 0x9c, 0x1c, + 0x2a, 0x0b, 0xbd, 0x1f, 0x1f, 0x31, 0xe6, 0x45, 0x81, 0xc6, 0xc5, 0x43, 0xe5, 0x53, 0x0e, 0x31, + 0x24, 0x87, 0x05, 0x03, 0xa6, 0x55, 0xac, 0x21, 0xd2, 0xdd, 0x4a, 0x9e, 0xf8, 0x5f, 0x18, 0xae, + 0x07, 0x55, 0xea, 0x3f, 0x4c, 0x48, 0x2d, 0xd6, 0xf3, 0xb8, 0x37, 0x53, 0x97, 0x21, 0x27, 0xef, + 0xb4, 0xaa, 0x76, 0xe6, 0x0b, 0x58, 0xe2, 0x94, 0x4e, 0xc0, 0xc8, 0x2d, 0x98, 0xe4, 0xfd, 0x09, + 0x3b, 0xc3, 0xe2, 0x88, 0x87, 0x10, 0x35, 0xf4, 0xe1, 0x38, 0xfa, 0x1f, 0xa5, 0xe1, 0x42, 0x2c, + 0x1e, 0xbf, 0xa7, 0xbb, 0x63, 0xf9, 0x56, 0x2b, 0x38, 0x61, 0x05, 0xdc, 0x18, 0x10, 0x4d, 0xdc, + 0x5f, 0xe0, 0x30, 0x45, 0x20, 0xbd, 0x4f, 0x20, 0x3c, 0x1a, 0xe3, 0x02, 0x49, 0x31, 0xc8, 0x26, + 0xa4, 0xab, 0x34, 0x14, 0xb7, 0x5d, 0xae, 0x0f, 0x68, 0x55, 0x95, 0x6b, 0xb1, 0x4a, 0x43, 0x3e, + 0x89, 0x78, 0x8f, 0x20, 0xa0, 0xea, 0x6d, 0x03, 0xc6, 0x85, 0x3c, 0x81, 0xc9, 0xb5, 0x43, 0x8f, + 0xd6, 0x43, 0x71, 0xc9, 0xe5, 0xe6, 0xf1, 0xfc, 0x38, 0xae, 0x72, 0x95, 0x86, 0x22, 0x40, 0x55, + 0x16, 0x47, 0x59, 0x78, 0x13, 0x72, 0xb2, 0xf3, 0xe7, 0xba, 0x4f, 0xf2, 0x16, 0x4c, 0x29, 0x9d, + 0x3c, 0x97, 0xd1, 0xff, 0x8f, 0x06, 0x93, 0xcc, 0x43, 0x9d, 0x5a, 0x8f, 0xf4, 0x7a, 0xc2, 0x23, + 0x9d, 0x53, 0x8e, 0xc6, 0xc7, 0xf2, 0x45, 0x5d, 0x0d, 0x20, 0x46, 0x26, 0xf7, 0x21, 0xbb, 0xed, + 0xf1, 0x0d, 0x5c, 0x4b, 0x94, 0x92, 0x19, 0x8e, 0x68, 0xa9, 0x5c, 0x92, 0xe1, 0x94, 0xeb, 0xf5, + 0xef, 0xb9, 0x92, 0x9a, 0xac, 0xc2, 0x44, 0xb9, 0xd9, 0x74, 0x9f, 0xf5, 0x5d, 0xdd, 0x61, 0x6c, + 0x56, 0xdc, 0xb6, 0xed, 0x70, 0x4e, 0x17, 0x05, 0xa7, 0xb3, 0x16, 0xc3, 0x55, 0x43, 0x47, 0x24, + 0x66, 0x29, 0xed, 0x2a, 0x6d, 0xcb, 0x6b, 0xec, 0x23, 0x98, 0x5c, 0x10, 0x4c, 0x66, 0x6d, 0xda, + 0x3e, 0x4a, 0xb8, 0x43, 0xda, 0x3e, 0xd2, 0x7f, 0x96, 0xe5, 0x07, 0xc9, 0x52, 0xb0, 0x77, 0x60, + 0xfa, 0x9e, 0xeb, 0x3f, 0xb3, 0x7c, 0xbb, 0xdc, 0xa0, 0x6d, 0x7e, 0xb3, 0x26, 0x87, 0x67, 0xe7, + 0x33, 0x4f, 0x39, 0xdc, 0xb4, 0x58, 0x43, 0x54, 0xae, 0x4d, 0xa0, 0x93, 0x6d, 0x98, 0x79, 0x60, + 0x1d, 0x8a, 0x82, 0xe5, 0xee, 0x2e, 0x4f, 0x73, 0xd3, 0x95, 0x9b, 0xbd, 0x6e, 0xe9, 0x52, 0xcb, + 0x3a, 0x94, 0x75, 0x4e, 0x33, 0x0c, 0x9b, 0x23, 0x1e, 0x53, 0x24, 0xe9, 0x89, 0x03, 0xb3, 0x3b, + 0xae, 0x1f, 0x8a, 0x4e, 0x9c, 0x76, 0x43, 0x0c, 0xb6, 0x20, 0x06, 0xcb, 0x64, 0xc0, 0xa8, 0xa9, + 0xb2, 0xf4, 0x5e, 0xb7, 0xa4, 0xfd, 0xbc, 0x5b, 0x02, 0x06, 0xe2, 0xc3, 0x61, 0xbd, 0xb2, 0x28, + 0xc9, 0x7c, 0x1a, 0x91, 0xab, 0xd5, 0xc6, 0x24, 0x63, 0xf2, 0x0e, 0x9c, 0x5b, 0xa1, 0x7e, 0xe8, + 0x3c, 0x75, 0xea, 0x56, 0x48, 0xef, 0xb9, 0x7e, 0xcb, 0x0a, 0xc5, 0x73, 0x14, 0x7c, 0x19, 0x56, + 0xa7, 0x9c, 0x53, 0xcb, 0x0a, 0x8d, 0x41, 0x4c, 0xf2, 0xe5, 0xd1, 0x67, 0x05, 0xaf, 0xb1, 0xc8, + 0x71, 0xc8, 0x59, 0xc1, 0x08, 0x15, 0x0c, 0x39, 0x35, 0x68, 0x1c, 0x7f, 0x6a, 0x70, 0x5b, 0x5c, + 0xa0, 0xf8, 0xd8, 0x88, 0x93, 0x83, 0x44, 0x47, 0xc7, 0x9e, 0x21, 0x2c, 0x43, 0xba, 0xb2, 0x73, + 0x0f, 0xef, 0x7e, 0x88, 0x02, 0x35, 0x6d, 0xef, 0x59, 0xed, 0x3a, 0xb5, 0xe3, 0xd3, 0x1d, 0xd5, + 0xe1, 0x55, 0x76, 0xee, 0x11, 0x0b, 0xe6, 0x76, 0xa8, 0xdf, 0x72, 0xc2, 0xff, 0x7f, 0xfb, 0xb6, + 0x32, 0x51, 0x39, 0x14, 0x6d, 0x49, 0x88, 0x56, 0xf2, 0x10, 0xc5, 0x3c, 0xbc, 0x7d, 0x7b, 0xe8, + 0x74, 0x44, 0x82, 0x0d, 0xe3, 0x45, 0xd6, 0x60, 0xf6, 0x81, 0x75, 0xb8, 0xc2, 0xe5, 0x8d, 0x02, + 0xe8, 0x74, 0xe5, 0x65, 0x69, 0x58, 0xf5, 0xb8, 0x49, 0x9d, 0xe2, 0x24, 0x11, 0xb9, 0x03, 0x53, + 0xb1, 0x79, 0x05, 0xe2, 0x18, 0x01, 0xcb, 0xbd, 0x8a, 0x71, 0x26, 0x2e, 0x71, 0x28, 0xe8, 0xe4, + 0x51, 0x94, 0xff, 0xf0, 0xe8, 0x11, 0x8b, 0xa0, 0xf9, 0xca, 0x92, 0x9a, 0xff, 0x58, 0xd8, 0x92, + 0x18, 0xd6, 0xd9, 0x28, 0xe2, 0xf5, 0xad, 0x90, 0x36, 0xe2, 0x94, 0x88, 0x73, 0x51, 0xd2, 0xaa, + 0x1d, 0xdf, 0x6d, 0x79, 0x21, 0x56, 0x43, 0xfb, 0xd2, 0x2a, 0x0f, 0x5b, 0x86, 0xa4, 0x55, 0x9c, + 0x44, 0xff, 0x65, 0x16, 0x66, 0x93, 0xeb, 0x9e, 0x6d, 0xc4, 0x5b, 0x6e, 0xc3, 0x69, 0xcb, 0x40, + 0x99, 0x5f, 0xd3, 0x44, 0x48, 0xe2, 0x01, 0x1b, 0x42, 0xc8, 0x27, 0x00, 0xa2, 0xea, 0x9f, 0xcc, + 0x75, 0xc5, 0x73, 0x3b, 0xa5, 0x81, 0x7c, 0x0d, 0xe0, 0xa1, 0x6b, 0x53, 0x71, 0x89, 0x33, 0x7d, + 0x5c, 0x12, 0xf3, 0x8a, 0x48, 0x62, 0xc4, 0x13, 0xb9, 0x5e, 0xb7, 0x34, 0xdf, 0x76, 0x6d, 0x3a, + 0x78, 0x31, 0x59, 0xe1, 0x48, 0xde, 0x86, 0x09, 0xa3, 0xd3, 0xa4, 0xf2, 0xe2, 0xe9, 0x94, 0x74, + 0x69, 0x9d, 0x26, 0x8d, 0xbd, 0xa1, 0xdf, 0xe9, 0xbf, 0x08, 0xc5, 0x00, 0xe4, 0x2e, 0xc0, 0x66, + 0xa7, 0x46, 0xef, 0xfb, 0x6e, 0xc7, 0x93, 0x17, 0xa7, 0x30, 0x14, 0xdf, 0x8f, 0xae, 0xef, 0x9a, + 0x0d, 0x6c, 0x54, 0x3b, 0x8f, 0x49, 0xc8, 0x36, 0x64, 0x85, 0x56, 0xc5, 0x23, 0xbe, 0x2b, 0xc3, + 0x6a, 0x0d, 0x8a, 0x6b, 0x15, 0x37, 0x41, 0x11, 0x9c, 0xbc, 0x09, 0xca, 0x53, 0x89, 0x3b, 0x90, + 0x67, 0xec, 0x59, 0xba, 0x10, 0x88, 0x25, 0x85, 0x47, 0x20, 0x8a, 0x40, 0x2c, 0xb5, 0x48, 0xdc, + 0xd2, 0x8e, 0x08, 0xc8, 0x97, 0x21, 0x5f, 0xf6, 0x3c, 0xa1, 0xea, 0x63, 0x93, 0xdb, 0xeb, 0x03, + 0xaa, 0x3e, 0x6f, 0x79, 0xde, 0x90, 0x2b, 0xe0, 0x11, 0x3f, 0xd2, 0x88, 0x6e, 0x14, 0x44, 0x2f, + 0x29, 0x8e, 0xe9, 0xe0, 0xd5, 0x81, 0x0e, 0x8a, 0xf2, 0xdc, 0x76, 0xf0, 0xe9, 0x44, 0x82, 0x2f, + 0xf1, 0xa0, 0x10, 0x5f, 0x9f, 0x16, 0x7d, 0xc1, 0x71, 0x7d, 0xbd, 0x36, 0xd0, 0x97, 0x3a, 0x81, + 0x03, 0xdd, 0x0d, 0x70, 0x27, 0x36, 0xcc, 0xca, 0x87, 0x20, 0xa2, 0xbf, 0xa9, 0xe3, 0xfa, 0xfb, + 0xc4, 0x40, 0x7f, 0x73, 0x76, 0x6d, 0xb0, 0x9f, 0x3e, 0x9e, 0xe4, 0x0e, 0xcc, 0x48, 0x08, 0xae, + 0x8f, 0xe2, 0x34, 0xce, 0x2f, 0x86, 0x3d, 0x76, 0x0d, 0x4f, 0xb6, 0x92, 0xd7, 0x95, 0x55, 0x64, + 0x95, 0x9a, 0x5b, 0xc7, 0x4c, 0x82, 0xba, 0xdf, 0x2a, 0x92, 0xc8, 0xfa, 0xdf, 0xa6, 0xe0, 0xe2, + 0x08, 0x9b, 0x8c, 0x6f, 0x0e, 0x6a, 0x27, 0xde, 0x1c, 0x74, 0x98, 0x0d, 0x58, 0x4e, 0x2b, 0xd8, + 0x75, 0xe3, 0x12, 0x57, 0x9c, 0x5d, 0x25, 0x7b, 0x60, 0x88, 0xf2, 0x36, 0xe1, 0xc7, 0xc4, 0x4a, + 0xbc, 0x54, 0x47, 0x72, 0x33, 0x74, 0x07, 0x52, 0xdc, 0x24, 0x67, 0xf2, 0x03, 0x0d, 0xa6, 0xd4, + 0xf2, 0xc7, 0xb1, 0x9e, 0xe3, 0x2b, 0x2f, 0xa6, 0xfc, 0x31, 0x3f, 0xbc, 0xee, 0xa1, 0xca, 0xc1, + 0xd2, 0xa3, 0x4b, 0x23, 0xc7, 0xc9, 0x74, 0x89, 0xbf, 0xd5, 0x67, 0xb1, 0x38, 0x64, 0x55, 0x97, + 0x88, 0xc1, 0x50, 0x1f, 0xc7, 0x21, 0x34, 0x47, 0xed, 0x3f, 0x6f, 0xe2, 0x18, 0xf1, 0x0c, 0xa5, + 0x4f, 0x9a, 0x21, 0xfd, 0x67, 0x1a, 0x64, 0x98, 0x73, 0x23, 0x6f, 0x40, 0x5e, 0x26, 0x34, 0xea, + 0x75, 0xad, 0x39, 0x99, 0xef, 0x24, 0x56, 0x79, 0x84, 0x89, 0x52, 0x51, 0xbf, 0x26, 0x1d, 0x3a, + 0x97, 0x8a, 0x01, 0x12, 0x52, 0x31, 0x00, 0x43, 0x7d, 0xb2, 0x47, 0x7d, 0xf9, 0x34, 0x05, 0x51, + 0x9f, 0x31, 0x80, 0x8a, 0x8a, 0x18, 0x64, 0x09, 0xb2, 0x65, 0xb1, 0x0b, 0x67, 0x90, 0x2f, 0xfa, + 0x41, 0x6b, 0x60, 0xf7, 0x95, 0x58, 0xfa, 0xc7, 0x20, 0x1f, 0xc5, 0x69, 0x2c, 0xd9, 0xe0, 0x9a, + 0xc2, 0xd0, 0x52, 0x28, 0x05, 0x13, 0x0d, 0x66, 0xdc, 0xa7, 0xf6, 0x6e, 0xd3, 0xf0, 0x44, 0x83, + 0x0d, 0x69, 0xac, 0x4b, 0x4d, 0x3f, 0x9e, 0x04, 0x88, 0x91, 0x49, 0x0d, 0x66, 0xb7, 0x37, 0x56, + 0x57, 0x36, 0x6c, 0xda, 0x0e, 0xb1, 0x3a, 0xd5, 0x77, 0x8f, 0x6c, 0xed, 0x30, 0xa4, 0x7e, 0xdb, + 0x6a, 0x0a, 0x84, 0xa3, 0x78, 0x49, 0xba, 0x8e, 0x5d, 0x37, 0x9d, 0x88, 0x4e, 0xf5, 0x60, 0x49, + 0x8e, 0xac, 0x8f, 0x6a, 0xf9, 0xc1, 0x96, 0xd2, 0x47, 0x6a, 0xcc, 0x3e, 0x02, 0xab, 0xd5, 0x1c, + 0xd1, 0x47, 0x92, 0x23, 0xd9, 0x83, 0xc2, 0x7d, 0x5c, 0xc4, 0x4a, 0x2f, 0xe9, 0xe3, 0x7b, 0xb9, + 0x26, 0x7a, 0x79, 0x89, 0xaf, 0xfe, 0xe1, 0xfd, 0x0c, 0x70, 0x8d, 0x57, 0x55, 0xe6, 0x44, 0xbf, + 0xf7, 0x3b, 0x1a, 0x4c, 0x72, 0x2f, 0x21, 0x66, 0x6b, 0x84, 0x1f, 0x7a, 0xf2, 0x62, 0xfc, 0x50, + 0x21, 0xc4, 0xff, 0xd4, 0xa0, 0x8b, 0xb7, 0x91, 0x55, 0x98, 0xac, 0x86, 0x56, 0xd8, 0x91, 0x1f, + 0x0d, 0x90, 0xd9, 0x24, 0xc6, 0x64, 0xbc, 0xa5, 0x52, 0x14, 0xea, 0x28, 0x04, 0xf8, 0x5b, 0xe5, + 0xc2, 0x31, 0xd4, 0x4f, 0x49, 0x64, 0x7f, 0xc5, 0x4f, 0x49, 0x6c, 0x41, 0x5e, 0x9c, 0x20, 0x54, + 0x8e, 0x44, 0xc8, 0x21, 0x13, 0xad, 0x08, 0xae, 0x3c, 0x33, 0xe3, 0x20, 0xb3, 0x96, 0x78, 0x0a, + 0x11, 0x21, 0x92, 0xed, 0xfe, 0x4b, 0x3f, 0xf1, 0xac, 0x47, 0x70, 0x71, 0xba, 0xc6, 0x6f, 0x13, + 0xc5, 0xb7, 0x81, 0x54, 0x86, 0x11, 0xae, 0xfe, 0x6d, 0x0d, 0x0a, 0xfd, 0xf6, 0xc2, 0x62, 0x7a, + 0x11, 0xe2, 0xbb, 0x7e, 0x54, 0xa5, 0xc6, 0x98, 0xbe, 0x2e, 0xc1, 0xc9, 0x4f, 0x59, 0xa8, 0xe8, + 0x64, 0x19, 0x72, 0x6c, 0xd9, 0xb5, 0xe3, 0x87, 0x01, 0xe8, 0x4f, 0x3a, 0x02, 0xa6, 0x96, 0xb8, + 0x24, 0x9e, 0xb2, 0x6a, 0xff, 0x3a, 0x05, 0x53, 0xca, 0x64, 0x91, 0x9b, 0x90, 0xdb, 0x08, 0xb6, + 0xdc, 0xfa, 0x3e, 0xb5, 0x45, 0xe6, 0x8c, 0x5f, 0x0a, 0x71, 0x02, 0xb3, 0x89, 0x40, 0x23, 0x6a, + 0x66, 0x51, 0x3f, 0xff, 0xef, 0x01, 0x0d, 0x02, 0xab, 0x21, 0x7b, 0xc7, 0xa8, 0x9f, 0x23, 0x9b, + 0x2d, 0xde, 0xa2, 0xee, 0xaa, 0x09, 0x12, 0xf2, 0x55, 0x00, 0x0e, 0x60, 0xf3, 0x3b, 0xc6, 0xd9, + 0xa1, 0x5c, 0xc0, 0xf3, 0xa2, 0x03, 0x96, 0x86, 0xf6, 0x1d, 0xf6, 0x28, 0x0c, 0xf1, 0x53, 0x06, + 0x6e, 0x7d, 0x7f, 0xfc, 0xef, 0x94, 0xc4, 0x9f, 0x32, 0x70, 0xeb, 0xfb, 0xe6, 0xf0, 0xd3, 0x24, + 0x95, 0xa5, 0xfe, 0x8f, 0x9a, 0x62, 0x70, 0xe4, 0x21, 0xe4, 0xa3, 0xa9, 0x11, 0xf5, 0x95, 0xb9, + 0xe8, 0x4d, 0x93, 0x80, 0x1b, 0xf4, 0x69, 0xe5, 0x25, 0x91, 0x52, 0xce, 0x45, 0x13, 0x9c, 0xb0, + 0x3f, 0x09, 0x24, 0x9f, 0x87, 0x0c, 0x2a, 0xe6, 0xe4, 0x8b, 0xe8, 0xd2, 0xb1, 0x67, 0x98, 0x46, + 0x50, 0x4c, 0xa4, 0x24, 0x9f, 0x12, 0x67, 0x01, 0xe9, 0xc4, 0x43, 0x30, 0x06, 0x62, 0x72, 0x44, + 0x1e, 0x3d, 0x3e, 0xf4, 0x50, 0x9f, 0x85, 0x6b, 0x30, 0xf7, 0x68, 0xf9, 0x9e, 0x41, 0x1b, 0x4e, + 0x10, 0xf2, 0xcc, 0x9e, 0x45, 0x71, 0xe4, 0x12, 0xa4, 0x0d, 0xeb, 0x99, 0x78, 0x52, 0x84, 0xe7, + 0xff, 0xbe, 0xf5, 0xcc, 0x60, 0x30, 0x72, 0x0b, 0xf2, 0x9b, 0xf4, 0x68, 0xdd, 0x6a, 0xdb, 0x4d, + 0x2a, 0x9e, 0x0e, 0xe1, 0x1d, 0xc9, 0x7d, 0x7a, 0x64, 0xee, 0x21, 0xd4, 0x88, 0x11, 0xb0, 0xb0, + 0xd9, 0xa9, 0x6d, 0x52, 0x5e, 0xff, 0x99, 0x16, 0x85, 0xcd, 0x4e, 0x0d, 0x4f, 0xa2, 0x79, 0x8b, + 0xfe, 0xcf, 0x29, 0x28, 0xf4, 0xaf, 0x35, 0x72, 0x17, 0xa6, 0xe5, 0x09, 0xf7, 0xba, 0x15, 0xec, + 0x09, 0x51, 0xf0, 0x6d, 0x8b, 0x27, 0xe0, 0xe6, 0x9e, 0x15, 0xa8, 0x8b, 0x30, 0x41, 0xc0, 0xf6, + 0xe0, 0x5d, 0x71, 0x0a, 0xae, 0xac, 0x99, 0xd0, 0x0d, 0xbd, 0xbe, 0xd7, 0x4d, 0x12, 0x8d, 0xd8, + 0x70, 0xb6, 0x4f, 0x17, 0x91, 0xb9, 0x0a, 0x9d, 0x0e, 0x6a, 0x8a, 0xe7, 0x4a, 0x9d, 0xe5, 0xa7, + 0xa6, 0xaf, 0xb4, 0xa8, 0x17, 0x95, 0xfa, 0x88, 0xc8, 0x5b, 0x00, 0x8f, 0x96, 0xef, 0xe1, 0xa5, + 0x43, 0xea, 0xa3, 0xbd, 0xce, 0xf0, 0x67, 0x1f, 0x8c, 0x49, 0x9d, 0x83, 0xd5, 0xdc, 0x2f, 0x46, + 0x26, 0x6f, 0x40, 0xfa, 0xc1, 0xbd, 0xb2, 0xa8, 0xd8, 0x4a, 0x9f, 0xf7, 0xe0, 0x5e, 0x79, 0x95, + 0x1e, 0x38, 0x75, 0xca, 0x6b, 0xbd, 0xad, 0xa7, 0xea, 0x71, 0x02, 0xc3, 0xd7, 0xff, 0x33, 0x05, + 0xf9, 0x08, 0x8b, 0x10, 0xc0, 0x48, 0x45, 0x94, 0x56, 0xf1, 0x7f, 0x72, 0x09, 0x72, 0x32, 0x38, + 0x11, 0xe5, 0xd5, 0x6c, 0x20, 0x02, 0x93, 0x22, 0xc8, 0x28, 0x84, 0x07, 0x26, 0x86, 0xfc, 0x49, + 0x6e, 0x43, 0x14, 0x62, 0x8c, 0x8a, 0x45, 0x32, 0xcc, 0xf8, 0x8c, 0x08, 0x8d, 0xcc, 0x42, 0xca, + 0xe1, 0x5f, 0x44, 0xc9, 0x1b, 0x29, 0xc7, 0x26, 0x77, 0x21, 0x67, 0xd9, 0x36, 0xb5, 0x4d, 0x2b, + 0x1c, 0xe3, 0x93, 0x34, 0x39, 0xc6, 0x8d, 0xef, 0x05, 0x48, 0x55, 0x0e, 0x49, 0x19, 0xf2, 0xf8, + 0x45, 0x92, 0x4e, 0x30, 0xd6, 0x67, 0x4c, 0x62, 0x0e, 0x39, 0x46, 0xf6, 0x28, 0xa0, 0x36, 0x79, + 0x05, 0x32, 0xcc, 0x28, 0xc4, 0x4e, 0x12, 0xbd, 0x24, 0xda, 0xde, 0xdd, 0xe1, 0x0a, 0x5b, 0x3f, + 0x63, 0x20, 0x02, 0xf9, 0x38, 0xa4, 0x3b, 0xcb, 0x4f, 0xc5, 0x1e, 0x51, 0x88, 0x4d, 0x22, 0x42, + 0x63, 0xcd, 0x95, 0x1c, 0x4c, 0xda, 0x08, 0xd0, 0xaf, 0x00, 0xc4, 0x5c, 0x06, 0x0b, 0xda, 0xfa, + 0x57, 0x21, 0x1f, 0x51, 0x93, 0x97, 0x41, 0x59, 0x40, 0xdc, 0xd8, 0x8d, 0xfc, 0x7e, 0xb4, 0x8c, + 0x2e, 0x42, 0xd6, 0x63, 0x13, 0x24, 0x5f, 0xeb, 0x19, 0x6c, 0x0d, 0x31, 0x9b, 0x2d, 0x42, 0x56, + 0xd8, 0x0c, 0x4e, 0xcf, 0x8c, 0x21, 0x7f, 0xea, 0x6d, 0x98, 0x56, 0x1d, 0x12, 0x8b, 0x58, 0x95, + 0x8b, 0xa3, 0xfd, 0x5f, 0x58, 0xe2, 0xa7, 0xa7, 0xa9, 0x81, 0xd3, 0xd3, 0x1b, 0x90, 0x93, 0x9b, + 0x98, 0xfa, 0x1e, 0x5c, 0xc4, 0x3b, 0x47, 0x46, 0xd4, 0xaa, 0xbf, 0x02, 0x59, 0xe1, 0x73, 0x8e, + 0x7f, 0x14, 0xac, 0x7f, 0x23, 0x05, 0x67, 0x0d, 0xca, 0xac, 0x48, 0xbc, 0xb4, 0xfe, 0x88, 0xbd, + 0x20, 0x4c, 0x8c, 0x6d, 0x74, 0x5c, 0xad, 0xff, 0x54, 0x83, 0xb9, 0x21, 0xb8, 0x1f, 0xe4, 0x95, + 0x00, 0x79, 0x13, 0xf2, 0xab, 0x8e, 0xd5, 0x2c, 0xdb, 0xb6, 0x2f, 0xf3, 0x28, 0x0c, 0x56, 0x6c, + 0x87, 0xc5, 0x2a, 0x0c, 0xaa, 0xee, 0x3e, 0x11, 0x2a, 0x79, 0x55, 0x18, 0x45, 0x3a, 0x52, 0xab, + 0x7c, 0xa3, 0x08, 0x5c, 0xa6, 0xf8, 0x85, 0xa2, 0xfe, 0x83, 0x14, 0x10, 0x0e, 0x8c, 0xab, 0x95, + 0xa7, 0x76, 0xea, 0xee, 0x26, 0xa6, 0x4e, 0x3e, 0xf1, 0xee, 0x1f, 0xde, 0x58, 0x59, 0xd1, 0xb7, + 0x53, 0x70, 0x61, 0x38, 0xe1, 0x07, 0x9a, 0xca, 0x5b, 0x90, 0xc7, 0xe7, 0x01, 0xca, 0x33, 0x50, + 0xdc, 0x5f, 0xf9, 0x5b, 0x02, 0xc4, 0x8f, 0x11, 0xc8, 0x53, 0x98, 0xd9, 0xb2, 0x82, 0x70, 0x9d, + 0x5a, 0x7e, 0x58, 0xa3, 0x56, 0x38, 0x46, 0x80, 0x15, 0x7d, 0x8f, 0x08, 0x3d, 0xe7, 0x9e, 0xa4, + 0xec, 0xff, 0x1e, 0x51, 0x82, 0x6d, 0x64, 0x28, 0x99, 0x31, 0x0c, 0xe5, 0x5d, 0x38, 0x5b, 0xa5, + 0x2d, 0xcb, 0xdb, 0x73, 0x7d, 0x2a, 0x0e, 0x73, 0x17, 0x61, 0x26, 0x02, 0x0d, 0xb5, 0x96, 0x64, + 0x73, 0x02, 0x5f, 0x51, 0x44, 0xec, 0x4a, 0x92, 0xcd, 0xfa, 0x8f, 0xb0, 0xd8, 0xf4, 0x6e, 0xc7, + 0xf1, 0x69, 0xd4, 0x20, 0x0b, 0x9c, 0x1f, 0x72, 0xdf, 0x64, 0x09, 0xf2, 0x0f, 0xac, 0x43, 0xfc, + 0x66, 0x5e, 0x20, 0xbe, 0xa7, 0xc7, 0x77, 0x62, 0xeb, 0xd0, 0x8c, 0x4a, 0x1f, 0x46, 0x8c, 0xf3, + 0x22, 0x3f, 0xab, 0xa7, 0xc3, 0xe4, 0xba, 0xdb, 0xb4, 0xa9, 0x2f, 0x2e, 0xaf, 0x63, 0x78, 0xb5, + 0x87, 0x10, 0x43, 0xb4, 0xe8, 0xff, 0xae, 0xc1, 0x6c, 0x24, 0x31, 0x8a, 0xf0, 0xa1, 0xab, 0xa4, + 0xef, 0x03, 0x83, 0xf9, 0x31, 0x3e, 0x30, 0x38, 0xf1, 0xab, 0x69, 0x42, 0xff, 0x73, 0x0d, 0xce, + 0x25, 0x47, 0xc9, 0x76, 0x22, 0x45, 0x10, 0x6d, 0x4c, 0x41, 0x52, 0x2f, 0x6c, 0x4a, 0xd2, 0x23, + 0xa7, 0xe4, 0x9b, 0x29, 0x98, 0x8a, 0x84, 0x3d, 0xb5, 0xc7, 0xd6, 0x9f, 0x4d, 0xf8, 0xd0, 0x0b, + 0xd1, 0xc7, 0x5f, 0xc4, 0xb8, 0xc6, 0x3a, 0xbb, 0xae, 0x2a, 0xbe, 0x42, 0x9c, 0x5f, 0x7f, 0x1e, + 0x26, 0xc5, 0x62, 0xd2, 0x12, 0x1f, 0x44, 0x19, 0x98, 0xdd, 0xca, 0xac, 0x60, 0x3d, 0x89, 0x13, + 0x1a, 0x18, 0x82, 0x0e, 0x2f, 0x2a, 0x3d, 0xa1, 0x35, 0x71, 0x26, 0x76, 0x6a, 0xf7, 0xa8, 0xe1, + 0x17, 0x95, 0xe2, 0x81, 0x8d, 0xb5, 0x3b, 0x7d, 0x3f, 0x0d, 0x85, 0x7e, 0x92, 0x93, 0x2f, 0x7f, + 0xef, 0x74, 0x6a, 0x22, 0xb7, 0xc3, 0xe4, 0xcf, 0xeb, 0xd4, 0x0c, 0x06, 0x23, 0xd7, 0x21, 0xb3, + 0xe3, 0x3b, 0x07, 0x22, 0x99, 0xc3, 0x4b, 0x39, 0x9e, 0xef, 0x1c, 0xa8, 0x27, 0xf6, 0xac, 0x1d, + 0x93, 0xaf, 0xad, 0xaa, 0xf2, 0x51, 0x2f, 0x9e, 0x7c, 0x35, 0x83, 0xfe, 0xaf, 0x7a, 0x49, 0x34, + 0xb6, 0x55, 0x56, 0xa8, 0xe5, 0x53, 0x9f, 0x3f, 0xa2, 0x9e, 0x88, 0xb7, 0xca, 0x1a, 0x82, 0xf9, + 0xa3, 0x53, 0x43, 0x45, 0x22, 0x4d, 0x20, 0xca, 0xcf, 0xf1, 0xbf, 0x6d, 0x29, 0x3f, 0xad, 0x75, + 0x5e, 0x65, 0x6d, 0xaa, 0xab, 0x79, 0x08, 0xdf, 0x17, 0x58, 0xc2, 0xd2, 0x7f, 0x88, 0x21, 0x70, + 0xcb, 0x0d, 0xa9, 0xd8, 0xf9, 0x4f, 0xad, 0x0f, 0x88, 0xab, 0x83, 0xdc, 0x4a, 0x2f, 0x47, 0x41, + 0xb0, 0x32, 0x3a, 0x8e, 0xf1, 0xf8, 0xf5, 0x78, 0xc1, 0xf2, 0x3a, 0xa1, 0xac, 0x0e, 0x2a, 0xe6, + 0xfa, 0xa7, 0x1a, 0xcc, 0x0f, 0xa5, 0x25, 0x8b, 0x00, 0x71, 0x7c, 0x25, 0xb4, 0xc4, 0x1f, 0x67, + 0x46, 0x50, 0x43, 0xc1, 0x20, 0x5f, 0xe9, 0x8f, 0x8c, 0x4e, 0x76, 0xec, 0xf2, 0x03, 0x14, 0xb3, + 0xc9, 0xc8, 0x68, 0x48, 0x3c, 0xa4, 0xff, 0x34, 0x0d, 0xe7, 0x06, 0xbe, 0xb8, 0x74, 0xc2, 0xd7, + 0x90, 0xf6, 0xfb, 0xbe, 0x5b, 0xc4, 0x2b, 0xd9, 0xaf, 0x8e, 0xfa, 0xde, 0xd3, 0x90, 0xaf, 0x18, + 0x61, 0xf9, 0x43, 0x3c, 0xc2, 0x3e, 0xe1, 0x63, 0x46, 0x41, 0xff, 0xc7, 0x8c, 0x78, 0x45, 0xfb, + 0x93, 0x23, 0x7b, 0x7b, 0x01, 0x9f, 0xa0, 0xfb, 0x3f, 0xfc, 0x55, 0xa1, 0x6f, 0xa4, 0x00, 0x9e, + 0xd0, 0xda, 0xe9, 0x7e, 0x1d, 0xf4, 0x99, 0xc4, 0x86, 0x30, 0x1f, 0x6f, 0x08, 0xe3, 0xbf, 0x09, + 0xda, 0x86, 0xd9, 0x24, 0xfe, 0xc9, 0x2f, 0x0b, 0xb8, 0x43, 0x4e, 0x0d, 0xff, 0xaa, 0x85, 0x5e, + 0x83, 0xf3, 0xf7, 0x69, 0x18, 0xef, 0x30, 0x32, 0xea, 0x3e, 0x9e, 0xed, 0x2d, 0xc8, 0x0b, 0xfc, + 0xe4, 0x43, 0x6b, 0x79, 0xf5, 0xca, 0xb1, 0x8d, 0x18, 0x41, 0xa7, 0x70, 0x71, 0x95, 0x36, 0x69, + 0x48, 0x3f, 0xdc, 0x6e, 0xaa, 0x40, 0xf8, 0x50, 0x70, 0x64, 0xe3, 0xf5, 0x70, 0xa2, 0x7e, 0x1e, + 0xc3, 0x7c, 0x24, 0xfb, 0x0b, 0xe4, 0xfb, 0xea, 0x5d, 0x98, 0x56, 0x2f, 0xa9, 0xf3, 0xaf, 0x5a, + 0x3f, 0x5c, 0x2b, 0x9c, 0x21, 0x53, 0x90, 0xdd, 0x59, 0x7b, 0xb8, 0xba, 0xf1, 0xf0, 0x7e, 0x41, + 0x23, 0xd3, 0x90, 0x2b, 0xef, 0xec, 0x18, 0xdb, 0x8f, 0xd7, 0x56, 0x0b, 0x29, 0x02, 0x30, 0xb9, + 0xba, 0xf6, 0x70, 0x63, 0x6d, 0xb5, 0x90, 0xae, 0x14, 0xde, 0xfb, 0xb7, 0x2b, 0x67, 0xde, 0xfb, + 0xc5, 0x15, 0xed, 0xef, 0x7f, 0x71, 0x45, 0xfb, 0xd7, 0x5f, 0x5c, 0xd1, 0x6a, 0x93, 0xe8, 0x12, + 0x5f, 0xff, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x42, 0x61, 0x3a, 0x0f, 0x5d, 0x00, 0x00, } diff --git a/api/types/types.proto b/api/types/types.proto index 6ce5b46eca5..4d4ad73ab06 100644 --- a/api/types/types.proto +++ b/api/types/types.proto @@ -1444,3 +1444,63 @@ message KubernetesCluster { map DynamicLabels = 3 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "dynamic_labels,omitempty" ]; } + +// WebTokenV3 describes a web token. Web tokens are used as a transport to relay bearer tokens +// to the client. +// Initially bound to a web session, these have been factored out into a separate resource to +// enable separate lifecycle management. +message WebTokenV3 { + 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 + string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ]; + // Version is the resource version + string Version = 3 [ (gogoproto.jsontag) = "version" ]; + // Metadata is resource metadata + Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ]; + // Spec defines the web token + WebTokenSpecV3 Spec = 5 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ]; +} + +// WebTokenSpecV3 is a unique time-limited token bound to a user's web session +message WebTokenSpecV3 { + // User specifies the user the token is bound to. + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // Token specifies the token's value. + string Token = 2 [ (gogoproto.jsontag) = "token" ]; +} + +// GetWebSessionRequest describes a request to query a web session +message GetWebSessionRequest { + // User specifies the user the web session is for. + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // SessionID specifies the web session ID. + string SessionID = 2 [ (gogoproto.jsontag) = "session_id" ]; +} + +// DeleteWebSessionRequest describes a request to delete a web session +message DeleteWebSessionRequest { + // User specifies the user the session is bound to + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // SessionID specifies the web session ID to delete. + string SessionID = 2 [ (gogoproto.jsontag) = "session_id" ]; +} + +// GetWebTokenRequest describes a request to query a web token +message GetWebTokenRequest { + // User specifies the user the token is for. + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // Token specifies the token to get. + string Token = 2 [ (gogoproto.jsontag) = "token" ]; +} + +// DeleteWebTokenRequest describes a request to delete a web token +message DeleteWebTokenRequest { + // User specifies the user the token is for. + string User = 1 [ (gogoproto.jsontag) = "user" ]; + // Token specifies the token to delete. + string Token = 2 [ (gogoproto.jsontag) = "token" ]; +} diff --git a/constants.go b/constants.go index e949be245f2..8016b328005 100644 --- a/constants.go +++ b/constants.go @@ -163,6 +163,9 @@ const ( // ComponentAppProxy is the application handler within the web proxy service. ComponentAppProxy = "app:web" + // ComponentWebProxy is the web handler within the web proxy service. + ComponentWebProxy = "web" + // ComponentDiagnostic is a diagnostic service ComponentDiagnostic = "diag" diff --git a/lib/auth/api.go b/lib/auth/api.go index 01bbbca1c71..aba07ce60c4 100644 --- a/lib/auth/api.go +++ b/lib/auth/api.go @@ -118,6 +118,12 @@ type ReadAccessPoint interface { // GetAppSession gets an application web session. GetAppSession(context.Context, services.GetAppSessionRequest) (services.WebSession, error) + // GetWebSession gets a web session for the given request + GetWebSession(context.Context, types.GetWebSessionRequest) (types.WebSession, error) + + // GetWebToken gets a web token for the given request + GetWebToken(context.Context, types.GetWebTokenRequest) (types.WebToken, error) + // GetRemoteClusters returns a list of remote clusters GetRemoteClusters(opts ...services.MarshalOption) ([]services.RemoteCluster, error) diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 3cdad67ec91..8a05faef5c3 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib" @@ -259,7 +260,7 @@ type HandlerWithAuthFunc func(auth ClientI, w http.ResponseWriter, r *http.Reque func (s *APIServer) withAuth(handler HandlerWithAuthFunc) httprouter.Handle { const accessDeniedMsg = "auth API: access denied " return httplib.MakeHandler(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - // HTTPS server expects auth context to be set by the auth middleware + // HTTPS server expects auth context to be set by the auth middleware authContext, err := s.Authorizer.Authorize(r.Context()) if err != nil { // propagate connection problem error so we can differentiate @@ -682,17 +683,20 @@ func (s *APIServer) deleteToken(auth ClientI, w http.ResponseWriter, r *http.Req } func (s *APIServer) deleteWebSession(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { - user, sid := p.ByName("user"), p.ByName("sid") - err := auth.DeleteWebSession(user, sid) + user, sessionID := p.ByName("user"), p.ByName("sid") + err := auth.WebSessions().Delete(r.Context(), types.DeleteWebSessionRequest{ + User: user, + SessionID: sessionID, + }) if err != nil { return nil, trace.Wrap(err) } - return message(fmt.Sprintf("session '%v' for user '%v' deleted", sid, user)), nil + return message(fmt.Sprintf("session %q for user %q deleted", sessionID, user)), nil } func (s *APIServer) getWebSession(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) { user, sid := p.ByName("user"), p.ByName("sid") - sess, err := auth.GetWebSessionInfo(user, sid) + sess, err := auth.GetWebSessionInfo(r.Context(), user, sid) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 9d911a06254..58d51d3cc69 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -158,6 +158,18 @@ type Services struct { events.IAuditLog } +// GetWebSession returns existing web session described by req. +// Implements ReadAccessPoint +func (r Services) GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + return r.Identity.WebSessions().Get(ctx, req) +} + +// GetWebToken returns existing web token described by req. +// Implements ReadAccessPoint +func (r Services) GetWebToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + return r.Identity.WebTokens().Get(ctx, req) +} + var ( generateRequestsCount = prometheus.NewCounter( prometheus.CounterOpts{ @@ -799,11 +811,15 @@ func (a *Server) PreAuthenticatedSignIn(user string, identity tlsca.Identity) (s if err != nil { return nil, trace.Wrap(err) } - sess, err := a.NewWebSession(user, roles, traits) + sess, err := a.NewWebSession(types.NewWebSessionRequest{ + User: user, + Roles: roles, + Traits: traits, + }) if err != nil { return nil, trace.Wrap(err) } - if err := a.UpsertWebSession(user, sess); err != nil { + if err := a.upsertWebSession(context.TODO(), user, sess); err != nil { return nil, trace.Wrap(err) } return sess.WithoutSecrets(), nil @@ -861,10 +877,14 @@ func (a *Server) CheckU2FSignResponse(ctx context.Context, user string, response return a.checkU2F(ctx, user, *response, a.Identity) } -// ExtendWebSession creates a new web session for a user based on a valid previous sessionID. +// ExtendWebSession creates a new web session for a user based on a valid previous session. // Additional roles are appended to initial roles if there is an approved access request. +// The new session expiration time will not exceed the expiration time of the old session. func (a *Server) ExtendWebSession(user, prevSessionID, accessRequestID string, identity tlsca.Identity) (services.WebSession, error) { - prevSession, err := a.GetWebSession(user, prevSessionID) + prevSession, err := a.GetWebSession(context.TODO(), types.GetWebSessionRequest{ + User: user, + SessionID: prevSessionID, + }) if err != nil { return nil, trace.Wrap(err) } @@ -897,15 +917,18 @@ func (a *Server) ExtendWebSession(user, prevSessionID, accessRequestID string, i } } - sess, err := a.NewWebSession(user, roles, traits) + sessionTTL := utils.ToTTL(a.clock, expiresAt) + sess, err := a.NewWebSession(types.NewWebSessionRequest{ + User: user, + Roles: roles, + Traits: traits, + SessionTTL: sessionTTL, + }) if err != nil { return nil, trace.Wrap(err) } - sess.SetExpiryTime(expiresAt) - bearerTokenTTL := utils.MinTTL(utils.ToTTL(a.clock, expiresAt), BearerTokenTTL) - sess.SetBearerTokenExpiryTime(a.clock.Now().UTC().Add(bearerTokenTTL)) - if err := a.UpsertWebSession(user, sess); err != nil { + if err := a.upsertWebSession(context.TODO(), user, sess); err != nil { return nil, trace.Wrap(err) } @@ -959,11 +982,15 @@ func (a *Server) CreateWebSession(user string) (services.WebSession, error) { if err != nil { return nil, trace.Wrap(err) } - sess, err := a.NewWebSession(user, u.GetRoles(), u.GetTraits()) + sess, err := a.NewWebSession(types.NewWebSessionRequest{ + User: user, + Roles: u.GetRoles(), + Traits: u.GetTraits(), + }) if err != nil { return nil, trace.Wrap(err) } - if err := a.UpsertWebSession(user, sess); err != nil { + if err := a.upsertWebSession(context.TODO(), user, sess); err != nil { return nil, trace.Wrap(err) } return sess, nil @@ -1468,27 +1495,30 @@ func (a *Server) GetTokens(opts ...services.MarshalOption) (tokens []services.Pr return tokens, nil } -func (a *Server) NewWebSession(username string, roles []string, traits wrappers.Traits) (services.WebSession, error) { - user, err := a.GetUser(username, false) +// NewWebSession creates and returns a new web session for the specified request +func (a *Server) NewWebSession(req types.NewWebSessionRequest) (services.WebSession, error) { + user, err := a.GetUser(req.User, false) if err != nil { return nil, trace.Wrap(err) } - checker, err := services.FetchRoles(roles, a.Access, traits) + checker, err := services.FetchRoles(req.Roles, a.Access, req.Traits) if err != nil { return nil, trace.Wrap(err) } - priv, pub, err := a.GetNewKeyPairFromPool() if err != nil { return nil, trace.Wrap(err) } - sessionTTL := checker.AdjustSessionTTL(defaults.CertDuration) + sessionTTL := req.SessionTTL + if sessionTTL == 0 { + sessionTTL = checker.AdjustSessionTTL(defaults.CertDuration) + } certs, err := a.generateUserCert(certRequest{ user: user, ttl: sessionTTL, publicKey: pub, checker: checker, - traits: traits, + traits: req.Traits, }) if err != nil { return nil, trace.Wrap(err) @@ -1503,7 +1533,7 @@ func (a *Server) NewWebSession(username string, roles []string, traits wrappers. } bearerTokenTTL := utils.MinTTL(sessionTTL, BearerTokenTTL) return services.NewWebSession(token, services.KindWebSession, services.KindWebSession, services.WebSessionSpecV2{ - User: user.GetName(), + User: req.User, Priv: priv, Pub: certs.ssh, TLSCert: certs.tls, @@ -1513,16 +1543,11 @@ func (a *Server) NewWebSession(username string, roles []string, traits wrappers. }), nil } -func (a *Server) UpsertWebSession(user string, sess services.WebSession) error { - return a.Identity.UpsertWebSession(user, sess.GetName(), sess) -} - -func (a *Server) GetWebSession(userName string, id string) (services.WebSession, error) { - return a.Identity.GetWebSession(userName, id) -} - -func (a *Server) GetWebSessionInfo(userName string, id string) (services.WebSession, error) { - sess, err := a.Identity.GetWebSession(userName, id) +// GetWebSessionInfo returns the web session specified with sessionID for the given user. +// The session is stripped of any authentication details. +// Implements auth.WebUIService +func (a *Server) GetWebSessionInfo(ctx context.Context, user, sessionID string) (services.WebSession, error) { + sess, err := a.Identity.WebSessions().Get(ctx, types.GetWebSessionRequest{User: user, SessionID: sessionID}) if err != nil { return nil, trace.Wrap(err) } @@ -1543,10 +1568,6 @@ func (a *Server) DeleteNamespace(namespace string) error { return a.Presence.DeleteNamespace(namespace) } -func (a *Server) DeleteWebSession(user string, id string) error { - return trace.Wrap(a.Identity.DeleteWebSession(user, id)) -} - // NewWatcher returns a new event watcher. In case of an auth server // this watcher will return events as seen by the auth server's // in memory cache, not the backend. @@ -2016,6 +2037,20 @@ func WithClock(clock clockwork.Clock) func(*Server) { } } +func (a *Server) upsertWebSession(ctx context.Context, user string, session services.WebSession) error { + if err := a.WebSessions().Upsert(ctx, session); err != nil { + return trace.Wrap(err) + } + token := types.NewWebToken(session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ + User: session.GetUser(), + Token: session.GetBearerToken(), + }) + if err := a.WebTokens().Upsert(ctx, token); err != nil { + return trace.Wrap(err) + } + return nil +} + // authKeepAliver is a keep aliver using auth server directly type authKeepAliver struct { sync.RWMutex diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index 7e207fc6cb4..23982ed4f0d 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -28,6 +28,7 @@ import ( "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth/testauthority" authority "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/backend" @@ -147,15 +148,21 @@ func (s *AuthSuite) TestSessions(c *C) { c.Assert(err, IsNil) c.Assert(ws, NotNil) - out, err := s.a.GetWebSessionInfo(user, ws.GetName()) + out, err := s.a.GetWebSessionInfo(context.TODO(), user, ws.GetName()) c.Assert(err, IsNil) ws.SetPriv(nil) fixtures.DeepCompare(c, ws, out) - err = s.a.DeleteWebSession(user, ws.GetName()) + err = s.a.WebSessions().Delete(context.TODO(), types.DeleteWebSessionRequest{ + User: user, + SessionID: ws.GetName(), + }) c.Assert(err, IsNil) - _, err = s.a.GetWebSession(user, ws.GetName()) + _, err = s.a.GetWebSession(context.TODO(), types.GetWebSessionRequest{ + User: user, + SessionID: ws.GetName(), + }) c.Assert(trace.IsNotFound(err), Equals, true, Commentf("%#v", err)) } diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index cd19623421f..5f04d148a10 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -125,8 +125,8 @@ func (a *ServerWithRoles) hasLocalUserRole(checker services.AccessChecker) bool return true } -// AuthenticateWebUser authenticates web user, creates and returns web session -// in case if authentication is successful +// AuthenticateWebUser authenticates web user, creates and returns a web session +// in case authentication is successful func (a *ServerWithRoles) AuthenticateWebUser(req AuthenticateUserRequest) (services.WebSession, error) { // authentication request has it's own authentication, however this limits the requests // types to proxies to make it harder to break @@ -489,6 +489,10 @@ func (a *ServerWithRoles) NewWatcher(ctx context.Context, watch services.Watch) if err := a.action(defaults.Namespace, services.KindWebSession, services.VerbRead); err != nil { return nil, trace.Wrap(err) } + case services.KindWebToken: + if err := a.action(defaults.Namespace, services.KindWebToken, services.VerbRead); err != nil { + return nil, trace.Wrap(err) + } case services.KindRemoteCluster: if err := a.action(defaults.Namespace, services.KindRemoteCluster, services.VerbRead); err != nil { return nil, trace.Wrap(err) @@ -778,6 +782,7 @@ func (a *ServerWithRoles) GetU2FSignRequest(user string, password []byte) (*u2f. return a.authServer.U2FSignRequest(user, password) } +// CreateWebSession creates a new web session for the specified user func (a *ServerWithRoles) CreateWebSession(user string) (services.WebSession, error) { if err := a.currentUserAction(user); err != nil { return nil, trace.Wrap(err) @@ -785,6 +790,9 @@ func (a *ServerWithRoles) CreateWebSession(user string) (services.WebSession, er return a.authServer.CreateWebSession(user) } +// ExtendWebSession creates a new web session for a user based on a valid previous session. +// Additional roles are appended to initial roles if there is an approved access request. +// The new session expiration time will not exceed the expiration time of the old session. func (a *ServerWithRoles) ExtendWebSession(user, prevSessionID, accessRequestID string) (services.WebSession, error) { if err := a.currentUserAction(user); err != nil { return nil, trace.Wrap(err) @@ -792,18 +800,148 @@ func (a *ServerWithRoles) ExtendWebSession(user, prevSessionID, accessRequestID return a.authServer.ExtendWebSession(user, prevSessionID, accessRequestID, a.context.Identity.GetIdentity()) } -func (a *ServerWithRoles) GetWebSessionInfo(user string, sid string) (services.WebSession, error) { +// GetWebSessionInfo returns the web session for the given user specified with sid. +// The session is stripped of any authentication details. +// Implements auth.WebUIService +func (a *ServerWithRoles) GetWebSessionInfo(ctx context.Context, user, sessionID string) (services.WebSession, error) { if err := a.currentUserAction(user); err != nil { return nil, trace.Wrap(err) } - return a.authServer.GetWebSessionInfo(user, sid) + return a.authServer.GetWebSessionInfo(ctx, user, sessionID) } -func (a *ServerWithRoles) DeleteWebSession(user string, sid string) error { - if err := a.currentUserAction(user); err != nil { +// GetWebSession returns the web session specified with req. +// Implements auth.ReadAccessPoint. +func (a *ServerWithRoles) GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + return a.WebSessions().Get(ctx, req) +} + +// WebSessions returns the web session manager. +// Implements services.WebSessionsGetter. +func (a *ServerWithRoles) WebSessions() types.WebSessionInterface { + return &webSessionsWithRoles{c: a, ws: a.authServer.WebSessions()} +} + +// Get returns the web session specified with req. +func (r *webSessionsWithRoles) Get(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + if err := r.c.currentUserAction(req.User); err != nil { + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbRead); err != nil { + return nil, trace.Wrap(err) + } + } + return r.ws.Get(ctx, req) +} + +// List returns the list of all web sessions. +func (r *webSessionsWithRoles) List(ctx context.Context) ([]services.WebSession, error) { + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbList); err != nil { + return nil, trace.Wrap(err) + } + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbRead); err != nil { + return nil, trace.Wrap(err) + } + return r.ws.List(ctx) +} + +// Upsert creates a new or updates the existing web session from the specified session. +// TODO(dmitri): this is currently only implemented for local invocations. This needs to be +// moved into a more appropriate API +func (*webSessionsWithRoles) Upsert(ctx context.Context, session services.WebSession) error { + return trace.NotImplemented(notImplementedMessage) +} + +// Delete removes the web session specified with req. +func (r *webSessionsWithRoles) Delete(ctx context.Context, req types.DeleteWebSessionRequest) error { + if err := r.c.currentUserAction(req.User); err != nil { + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbDelete); err != nil { + return trace.Wrap(err) + } + } + return r.ws.Delete(ctx, req) +} + +// DeleteAll removes all web sessions. +func (r *webSessionsWithRoles) DeleteAll(ctx context.Context) error { + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbList); err != nil { return trace.Wrap(err) } - return a.authServer.DeleteWebSession(user, sid) + if err := r.c.action(defaults.Namespace, services.KindWebSession, services.VerbDelete); err != nil { + return trace.Wrap(err) + } + return r.ws.DeleteAll(ctx) +} + +// GetWebToken returns the web token specified with req. +// Implements auth.ReadAccessPoint. +func (a *ServerWithRoles) GetWebToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + return a.WebTokens().Get(ctx, req) +} + +type webSessionsWithRoles struct { + c accessChecker + ws types.WebSessionInterface +} + +// WebTokens returns the web token manager. +// Implements services.WebTokensGetter. +func (a *ServerWithRoles) WebTokens() types.WebTokenInterface { + return &webTokensWithRoles{c: a, t: a.authServer.WebTokens()} +} + +// Get returns the web token specified with req. +func (r *webTokensWithRoles) Get(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + if err := r.c.currentUserAction(req.User); err != nil { + if err := r.c.action(defaults.Namespace, services.KindWebToken, services.VerbRead); err != nil { + return nil, trace.Wrap(err) + } + } + return r.t.Get(ctx, req) +} + +// List returns the list of all web tokens. +func (r *webTokensWithRoles) List(ctx context.Context) ([]types.WebToken, error) { + if err := r.c.action(defaults.Namespace, services.KindWebToken, services.VerbList); err != nil { + return nil, trace.Wrap(err) + } + return r.t.List(ctx) +} + +// Upsert creates a new or updates the existing web token from the specified token. +// TODO(dmitri): this is currently only implemented for local invocations. This needs to be +// moved into a more appropriate API +func (*webTokensWithRoles) Upsert(ctx context.Context, session types.WebToken) error { + return trace.NotImplemented(notImplementedMessage) +} + +// Delete removes the web token specified with req. +func (r *webTokensWithRoles) Delete(ctx context.Context, req types.DeleteWebTokenRequest) error { + if err := r.c.currentUserAction(req.User); err != nil { + if err := r.c.action(defaults.Namespace, services.KindWebToken, services.VerbDelete); err != nil { + return trace.Wrap(err) + } + } + return r.t.Delete(ctx, req) +} + +// DeleteAll removes all web tokens. +func (r *webTokensWithRoles) DeleteAll(ctx context.Context) error { + if err := r.c.action(defaults.Namespace, services.KindWebToken, services.VerbList); err != nil { + return trace.Wrap(err) + } + if err := r.c.action(defaults.Namespace, services.KindWebToken, services.VerbDelete); err != nil { + return trace.Wrap(err) + } + return r.t.DeleteAll(ctx) +} + +type webTokensWithRoles struct { + c accessChecker + t types.WebTokenInterface +} + +type accessChecker interface { + action(namespace, resource, action string) error + currentUserAction(user string) error } func (a *ServerWithRoles) GetAccessRequests(ctx context.Context, filter services.AccessRequestFilter) ([]services.AccessRequest, error) { diff --git a/lib/auth/clt.go b/lib/auth/clt.go index 4147bede783..673c9012be7 100644 --- a/lib/auth/clt.go +++ b/lib/auth/clt.go @@ -1152,16 +1152,16 @@ func (c *Client) AuthenticateSSHUser(req AuthenticateSSHRequest) (*SSHLoginRespo // GetWebSessionInfo checks if a web sesion is valid, returns session id in case if // it is valid, or error otherwise. -func (c *Client) GetWebSessionInfo(user string, sid string) (services.WebSession, error) { +func (c *Client) GetWebSessionInfo(ctx context.Context, user, sessionID string) (services.WebSession, error) { out, err := c.Get( - c.Endpoint("users", user, "web", "sessions", sid), url.Values{}) + c.Endpoint("users", user, "web", "sessions", sessionID), url.Values{}) if err != nil { return nil, trace.Wrap(err) } return services.UnmarshalWebSession(out.Bytes()) } -// DeleteWebSession deletes a web session for this user by id +// DeleteWebSession deletes the web session specified with sid for the given user func (c *Client) DeleteWebSession(user string, sid string) error { _, err := c.Delete(c.Endpoint("users", user, "web", "sessions", sid)) return trace.Wrap(err) @@ -2155,14 +2155,12 @@ func (c *Client) CreateAuditStream(ctx context.Context, sid session.ID) (events. type WebService interface { // GetWebSessionInfo checks if a web sesion is valid, returns session id in case if // it is valid, or error otherwise. - GetWebSessionInfo(user string, sid string) (services.WebSession, error) + GetWebSessionInfo(ctx context.Context, user, sessionID string) (types.WebSession, error) // ExtendWebSession creates a new web session for a user based on another // valid web session - ExtendWebSession(user string, prevSessionID string, accessRequestID string) (services.WebSession, error) + ExtendWebSession(user, prevSessionID, accessRequestID string) (types.WebSession, error) // CreateWebSession creates a new web session for a user - CreateWebSession(user string) (services.WebSession, error) - // DeleteWebSession deletes a web session for this user by id - DeleteWebSession(user string, sid string) error + CreateWebSession(user string) (types.WebSession, error) // AppSession defines application session features. services.AppSession @@ -2349,6 +2347,9 @@ type ClientI interface { services.ClusterConfiguration services.Events + types.WebSessionsGetter + types.WebTokensGetter + // NewKeepAliver returns a new instance of keep aliver NewKeepAliver(ctx context.Context) (services.KeepAliver, error) @@ -2395,4 +2396,12 @@ type ClientI interface { // GenerateDatabaseCert generates client certificate used by a database // service to authenticate with the database instance. GenerateDatabaseCert(context.Context, *proto.DatabaseCertRequest) (*proto.DatabaseCertResponse, error) + + // GetWebSession queries the existing web session described with req. + // Implements ReadAccessPoint. + GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) + + // GetWebToken queries the existing web token described with req. + // Implements ReadAccessPoint. + GetWebToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) } diff --git a/lib/auth/github.go b/lib/auth/github.go index c78ca189c7b..c6d00b55ecb 100644 --- a/lib/auth/github.go +++ b/lib/auth/github.go @@ -26,6 +26,7 @@ import ( "time" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/modules" @@ -259,7 +260,12 @@ func (a *Server) validateGithubAuthCallback(q url.Values) (*githubAuthResponse, // If the request is coming from a browser, create a web session. if req.CreateWebSession { - session, err := a.createWebSession(user, params.sessionTTL) + session, err := a.createWebSession(context.TODO(), types.NewWebSessionRequest{ + User: user.GetName(), + Roles: user.GetRoles(), + Traits: user.GetTraits(), + SessionTTL: params.sessionTTL, + }) if err != nil { return nil, trace.Wrap(err) } @@ -296,23 +302,16 @@ func (a *Server) validateGithubAuthCallback(q url.Values) (*githubAuthResponse, return re, nil } -func (a *Server) createWebSession(user services.User, sessionTTL time.Duration) (services.WebSession, error) { +func (a *Server) createWebSession(ctx context.Context, req types.NewWebSessionRequest) (services.WebSession, error) { // It's safe to extract the roles and traits directly from services.User // because this occurs during the user creation process and services.User // is not fetched from the backend. - session, err := a.NewWebSession(user.GetName(), user.GetRoles(), user.GetTraits()) + session, err := a.NewWebSession(req) if err != nil { return nil, trace.Wrap(err) } - // Session expiry time is the same as the user expiry time. - session.SetExpiryTime(a.clock.Now().UTC().Add(sessionTTL)) - - // Bearer tokens expire quicker than the overall session time and need to be refreshed. - bearerTTL := utils.MinTTL(BearerTokenTTL, sessionTTL) - session.SetBearerTokenExpiryTime(a.clock.Now().UTC().Add(bearerTTL)) - - err = a.UpsertWebSession(user.GetName(), session) + err = a.upsertWebSession(ctx, req.User, session) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 230e9ba9c70..f33b59980eb 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -229,12 +229,7 @@ func (g *GRPCServer) WatchEvents(watch *proto.Watch, stream proto.AuthService_Wa Name: auth.User.GetName(), } for _, kind := range watch.Kinds { - servicesWatch.Kinds = append(servicesWatch.Kinds, services.WatchKind{ - Name: kind.Name, - Kind: kind.Kind, - LoadSecrets: kind.LoadSecrets, - Filter: kind.Filter, - }) + servicesWatch.Kinds = append(servicesWatch.Kinds, proto.ToWatchKind(kind)) } watcher, err := auth.NewWatcher(stream.Context(), servicesWatch) if err != nil { @@ -971,6 +966,156 @@ func (g GRPCServer) GenerateAppToken(ctx context.Context, req *proto.GenerateApp }, nil } +// GetWebSession gets a web session. +func (g *GRPCServer) GetWebSession(ctx context.Context, req *types.GetWebSessionRequest) (*proto.GetWebSessionResponse, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + session, err := auth.WebSessions().Get(ctx, *req) + if err != nil { + return nil, trail.ToGRPC(err) + } + sess, ok := session.(*services.WebSessionV2) + if !ok { + return nil, trail.ToGRPC(trace.BadParameter("unexpected session type %T", session)) + } + + return &proto.GetWebSessionResponse{ + Session: sess, + }, nil +} + +// GetWebSessions gets all web sessions. +func (g *GRPCServer) GetWebSessions(ctx context.Context, _ *empty.Empty) (*proto.GetWebSessionsResponse, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + sessions, err := auth.WebSessions().List(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + var out []*services.WebSessionV2 + for _, session := range sessions { + sess, ok := session.(*services.WebSessionV2) + if !ok { + return nil, trail.ToGRPC(trace.BadParameter("unexpected type %T", session)) + } + out = append(out, sess) + } + + return &proto.GetWebSessionsResponse{ + Sessions: out, + }, nil +} + +// DeleteWebSession removes the web session given with req. +func (g *GRPCServer) DeleteWebSession(ctx context.Context, req *types.DeleteWebSessionRequest) (*empty.Empty, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + if err := auth.WebSessions().Delete(ctx, *req); err != nil { + return nil, trail.ToGRPC(err) + } + + return &empty.Empty{}, nil +} + +// DeleteAllWebSessions removes all web sessions. +func (g *GRPCServer) DeleteAllWebSessions(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + if err := auth.WebSessions().DeleteAll(ctx); err != nil { + return nil, trail.ToGRPC(err) + } + + return &empty.Empty{}, nil +} + +// GetWebToken gets a web token. +func (g *GRPCServer) GetWebToken(ctx context.Context, req *types.GetWebTokenRequest) (*proto.GetWebTokenResponse, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + resp, err := auth.WebTokens().Get(ctx, *req) + if err != nil { + return nil, trail.ToGRPC(err) + } + token, ok := resp.(*types.WebTokenV3) + if !ok { + return nil, trail.ToGRPC(trace.BadParameter("unexpected web token type %T", resp)) + } + + return &proto.GetWebTokenResponse{ + Token: token, + }, nil +} + +// GetWebTokens gets all web tokens. +func (g *GRPCServer) GetWebTokens(ctx context.Context, _ *empty.Empty) (*proto.GetWebTokensResponse, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + tokens, err := auth.WebTokens().List(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + var out []*types.WebTokenV3 + for _, t := range tokens { + token, ok := t.(*types.WebTokenV3) + if !ok { + return nil, trail.ToGRPC(trace.BadParameter("unexpected type %T", t)) + } + out = append(out, token) + } + + return &proto.GetWebTokensResponse{ + Tokens: out, + }, nil +} + +// DeleteWebToken removes the web token given with req. +func (g *GRPCServer) DeleteWebToken(ctx context.Context, req *types.DeleteWebTokenRequest) (*empty.Empty, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + if err := auth.WebTokens().Delete(ctx, *req); err != nil { + return nil, trail.ToGRPC(err) + } + + return &empty.Empty{}, nil +} + +// DeleteAllWebTokens removes all web tokens. +func (g *GRPCServer) DeleteAllWebTokens(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trail.ToGRPC(err) + } + + if err := auth.WebTokens().DeleteAll(ctx); err != nil { + return nil, trail.ToGRPC(err) + } + + return &empty.Empty{}, nil +} + // UpdateRemoteCluster updates remote cluster func (g *GRPCServer) UpdateRemoteCluster(ctx context.Context, req *services.RemoteClusterV3) (*empty.Empty, error) { auth, err := g.authenticate(ctx) @@ -1389,7 +1534,7 @@ type grpcContext struct { // authenticate extracts authentication context and returns initialized auth server func (g *GRPCServer) authenticate(ctx context.Context) (*grpcContext, error) { - // HTTPS server expects auth context to be set by the auth middleware + // HTTPS server expects auth context to be set by the auth middleware authContext, err := g.Authorizer.Authorize(ctx) if err != nil { // propagate connection problem error so we can differentiate diff --git a/lib/auth/methods.go b/lib/auth/methods.go index 756238f559c..7cc34c6a614 100644 --- a/lib/auth/methods.go +++ b/lib/auth/methods.go @@ -23,6 +23,7 @@ import ( "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth/u2f" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" @@ -166,10 +167,9 @@ func (s *Server) authenticateUser(ctx context.Context, req AuthenticateUserReque } } -// AuthenticateWebUser authenticates web user, creates and returns web session -// in case if authentication is successful. In case if existing session id -// is used to authenticate, returns session associated with the existing session id -// instead of creating the new one +// AuthenticateWebUser authenticates web user, creates and returns a web session +// if authentication is successful. In case the existing session ID is used to authenticate, +// returns the existing session instead of creating a new one func (s *Server) AuthenticateWebUser(req AuthenticateUserRequest) (services.WebSession, error) { clusterConfig, err := s.GetClusterConfig() if err != nil { @@ -186,7 +186,10 @@ func (s *Server) AuthenticateWebUser(req AuthenticateUserRequest) (services.WebS } if req.Session != nil { - session, err := s.GetWebSession(req.Username, req.Session.ID) + session, err := s.GetWebSession(context.TODO(), types.GetWebSessionRequest{ + User: req.Username, + SessionID: req.Session.ID, + }) if err != nil { return nil, trace.AccessDenied("session is invalid or has expired") } @@ -202,7 +205,7 @@ func (s *Server) AuthenticateWebUser(req AuthenticateUserRequest) (services.WebS return nil, trace.Wrap(err) } - sess, err := s.createUserWebSession(user) + sess, err := s.createUserWebSession(context.TODO(), user) if err != nil { return nil, trace.Wrap(err) } @@ -380,19 +383,14 @@ func (s *Server) emitNoLocalAuthEvent(username string) { } } -func (s *Server) createUserWebSession(user services.User) (services.WebSession, error) { - // It's safe to extract the roles and traits directly from services.User as this method +func (s *Server) createUserWebSession(ctx context.Context, 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 + return s.createWebSession(ctx, types.NewWebSessionRequest{ + User: user.GetName(), + Roles: user.GetRoles(), + Traits: user.GetTraits(), + }) } const noLocalAuth = "local auth disabled" diff --git a/lib/auth/oidc.go b/lib/auth/oidc.go index 0089f53bcd1..2adf73214a8 100644 --- a/lib/auth/oidc.go +++ b/lib/auth/oidc.go @@ -25,6 +25,7 @@ import ( "net/url" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" @@ -388,7 +389,12 @@ func (a *Server) validateOIDCAuthCallback(q url.Values) (*oidcAuthResponse, erro // If the request is coming from a browser, create a web session. if req.CreateWebSession { - session, err := a.createWebSession(user, params.sessionTTL) + session, err := a.createWebSession(context.TODO(), types.NewWebSessionRequest{ + User: user.GetName(), + Roles: user.GetRoles(), + Traits: user.GetTraits(), + SessionTTL: params.sessionTTL, + }) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/password.go b/lib/auth/password.go index d5bcda9fd3e..200d554b16d 100644 --- a/lib/auth/password.go +++ b/lib/auth/password.go @@ -42,7 +42,7 @@ func (s *Server) ChangePasswordWithToken(ctx context.Context, req ChangePassword return nil, trace.Wrap(err) } - sess, err := s.createUserWebSession(user) + sess, err := s.createUserWebSession(ctx, user) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/permissions.go b/lib/auth/permissions.go index 544b5cd0de6..7b6b6f5b758 100644 --- a/lib/auth/permissions.go +++ b/lib/auth/permissions.go @@ -280,6 +280,7 @@ func GetCheckerForBuiltinRole(clusterName string, clusterConfig services.Cluster services.NewRule(services.KindClusterConfig, services.RO()), services.NewRule(services.KindAppServer, services.RW()), services.NewRule(services.KindWebSession, services.RO()), + services.NewRule(services.KindWebToken, services.RO()), services.NewRule(services.KindJWT, services.RW()), }, }, @@ -343,6 +344,7 @@ func GetCheckerForBuiltinRole(clusterName string, clusterConfig services.Cluster services.NewRule(services.KindSemaphore, services.RW()), services.NewRule(services.KindAppServer, services.RO()), services.NewRule(services.KindWebSession, services.RW()), + services.NewRule(services.KindWebToken, services.RW()), services.NewRule(services.KindKubeService, services.RW()), services.NewRule(types.KindDatabaseServer, services.RO()), // this rule allows local proxy to update the remote cluster's host certificate authorities @@ -399,6 +401,7 @@ func GetCheckerForBuiltinRole(clusterName string, clusterConfig services.Cluster services.NewRule(services.KindSemaphore, services.RW()), services.NewRule(services.KindAppServer, services.RO()), services.NewRule(services.KindWebSession, services.RW()), + services.NewRule(services.KindWebToken, services.RW()), services.NewRule(services.KindKubeService, services.RW()), services.NewRule(types.KindDatabaseServer, services.RO()), // this rule allows local proxy to update the remote cluster's host certificate authorities @@ -429,6 +432,7 @@ func GetCheckerForBuiltinRole(clusterName string, clusterConfig services.Cluster Namespaces: []string{services.Wildcard}, Rules: []services.Rule{ services.NewRule(services.KindWebSession, services.RW()), + services.NewRule(services.KindWebToken, services.RW()), services.NewRule(services.KindSSHSession, services.RW()), services.NewRule(services.KindAuthServer, services.RO()), services.NewRule(services.KindUser, services.RO()), diff --git a/lib/auth/saml.go b/lib/auth/saml.go index cd1f4078d77..7cff1d66347 100644 --- a/lib/auth/saml.go +++ b/lib/auth/saml.go @@ -24,6 +24,7 @@ import ( "io/ioutil" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" @@ -403,7 +404,12 @@ func (a *Server) validateSAMLResponse(samlResponse string) (*samlAuthResponse, e // If the request is coming from a browser, create a web session. if request.CreateWebSession { - session, err := a.createWebSession(user, params.sessionTTL) + session, err := a.createWebSession(context.TODO(), types.NewWebSessionRequest{ + User: user.GetName(), + Roles: user.GetRoles(), + Traits: user.GetTraits(), + SessionTTL: params.sessionTTL, + }) if err != nil { return re, trace.Wrap(err) } diff --git a/lib/auth/sessions.go b/lib/auth/sessions.go index 82b1d9b06f4..10f823062cc 100644 --- a/lib/auth/sessions.go +++ b/lib/auth/sessions.go @@ -21,11 +21,14 @@ import ( "time" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/wrappers" "github.com/gravitational/teleport/lib/jwt" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/trace" + "github.com/pborman/uuid" ) @@ -35,7 +38,10 @@ import ( // control is enforced. func (s *Server) CreateAppSession(ctx context.Context, req services.CreateAppSessionRequest, user services.User, checker services.AccessChecker) (services.WebSession, error) { // Check that a matching parent web session exists in the backend. - parentSession, err := s.GetWebSession(req.Username, req.ParentSession) + parentSession, err := s.GetWebSession(ctx, types.GetWebSessionRequest{ + User: req.Username, + SessionID: req.ParentSession, + }) if err != nil { return nil, trace.Wrap(err) } @@ -57,7 +63,7 @@ func (s *Server) CreateAppSession(ctx context.Context, req services.CreateAppSes // used to log into servers but SSH certificate generation code requires a // principal be in the certificate. traits: wrappers.Traits(map[string][]string{ - teleport.TraitLogins: []string{uuid.New()}, + teleport.TraitLogins: {uuid.New()}, }), // Only allow this certificate to be used for applications. usage: []string{teleport.UsageAppsOnly}, diff --git a/lib/auth/tls_test.go b/lib/auth/tls_test.go index 322696cf986..73f48152f63 100644 --- a/lib/auth/tls_test.go +++ b/lib/auth/tls_test.go @@ -1434,7 +1434,7 @@ func (s *TLSSuite) TestWebSessionWithoutAccessRequest(c *check.C) { web, err := s.server.NewClientFromWebSession(ws) c.Assert(err, check.IsNil) - _, err = web.GetWebSessionInfo(user, ws.GetName()) + _, err = web.GetWebSessionInfo(context.TODO(), user, ws.GetName()) c.Assert(err, check.IsNil) new, err := web.ExtendWebSession(user, ws.GetName(), "") @@ -1448,7 +1448,7 @@ func (s *TLSSuite) TestWebSessionWithoutAccessRequest(c *check.C) { err = clt.DeleteWebSession(user, ws.GetName()) c.Assert(err, check.IsNil) - _, err = web.GetWebSessionInfo(user, ws.GetName()) + _, err = web.GetWebSessionInfo(context.TODO(), user, ws.GetName()) c.Assert(err, check.NotNil) _, err = web.ExtendWebSession(user, ws.GetName(), "") @@ -2246,13 +2246,13 @@ func (s *TLSSuite) TestAuthenticateWebUserOTP(c *check.C) { userClient, err := s.server.NewClientFromWebSession(ws) c.Assert(err, check.IsNil) - _, err = userClient.GetWebSessionInfo(user, ws.GetName()) + _, err = userClient.GetWebSessionInfo(context.TODO(), user, ws.GetName()) c.Assert(err, check.IsNil) err = clt.DeleteWebSession(user, ws.GetName()) c.Assert(err, check.IsNil) - _, err = userClient.GetWebSessionInfo(user, ws.GetName()) + _, err = userClient.GetWebSessionInfo(context.TODO(), user, ws.GetName()) c.Assert(err, check.NotNil) } diff --git a/lib/cache/cache.go b/lib/cache/cache.go index abf6a42a4db..84454b0663c 100644 --- a/lib/cache/cache.go +++ b/lib/cache/cache.go @@ -58,7 +58,9 @@ func ForAuth(cfg Config) Config { {Kind: services.KindTunnelConnection}, {Kind: services.KindAccessRequest}, {Kind: services.KindAppServer}, - {Kind: services.KindWebSession}, + {Kind: services.KindWebSession, SubKind: services.KindAppSession}, + {Kind: services.KindWebSession, SubKind: services.KindWebSession}, + {Kind: services.KindWebToken}, {Kind: services.KindRemoteCluster}, {Kind: services.KindKubeService}, {Kind: types.KindDatabaseServer}, @@ -83,7 +85,9 @@ func ForProxy(cfg Config) Config { {Kind: services.KindReverseTunnel}, {Kind: services.KindTunnelConnection}, {Kind: services.KindAppServer}, - {Kind: services.KindWebSession}, + {Kind: services.KindWebSession, SubKind: services.KindAppSession}, + {Kind: services.KindWebSession, SubKind: services.KindWebSession}, + {Kind: services.KindWebToken}, {Kind: services.KindRemoteCluster}, {Kind: services.KindKubeService}, {Kind: types.KindDatabaseServer}, @@ -262,8 +266,8 @@ type Cache struct { // cancel triggers exit context closure cancel context.CancelFunc - // collections is a map of registered collections by resource Kind - collections map[string]collection + // collections is a map of registered collections by resource Kind/SubKind + collections map[resourceKind]collection trustCache services.Trust clusterConfigCache services.ClusterConfiguration @@ -273,6 +277,8 @@ type Cache struct { dynamicAccessCache services.DynamicAccessExt presenceCache services.Presence appSessionCache services.AppSession + webSessionCache types.WebSessionInterface + webTokenCache types.WebTokenInterface eventsFanout *services.Fanout // closed indicates that the cache has been closed @@ -321,6 +327,8 @@ func (c *Cache) read() (readGuard, error) { dynamicAccess: c.dynamicAccessCache, presence: c.presenceCache, appSession: c.appSessionCache, + webSession: c.webSessionCache, + webToken: c.webTokenCache, release: c.rw.RUnlock, }, nil } @@ -334,6 +342,8 @@ func (c *Cache) read() (readGuard, error) { dynamicAccess: c.Config.DynamicAccess, presence: c.Config.Presence, appSession: c.Config.AppSession, + webSession: c.Config.WebSession, + webToken: c.Config.WebToken, release: nil, }, nil } @@ -351,6 +361,8 @@ type readGuard struct { dynamicAccess services.DynamicAccess presence services.Presence appSession services.AppSession + webSession types.WebSessionInterface + webToken types.WebTokenInterface release func() released bool } @@ -398,6 +410,10 @@ type Config struct { Presence services.Presence // AppSession holds application sessions. AppSession services.AppSession + // WebSession holds regular web sessions. + WebSession types.WebSessionInterface + // WebToken holds web tokens. + WebToken types.WebTokenInterface // Backend is a backend for local cache Backend backend.Backend // RetryPeriod is a period between cache retries on failures @@ -540,6 +556,8 @@ func New(config Config) (*Cache, error) { dynamicAccessCache: local.NewDynamicAccessService(wrapper), presenceCache: local.NewPresenceService(wrapper), appSessionCache: local.NewIdentityService(wrapper), + webSessionCache: local.NewIdentityService(wrapper).WebSessions(), + webTokenCache: local.NewIdentityService(wrapper).WebTokens(), eventsFanout: services.NewFanout(), Entry: log.WithFields(log.Fields{ trace.Component: config.Component, @@ -893,9 +911,11 @@ func (c *Cache) fetch(ctx context.Context) (apply func(ctx context.Context) erro } func (c *Cache) processEvent(ctx context.Context, event services.Event) error { - collection, ok := c.collections[event.Resource.GetKind()] + resourceKind := resourceKindFromResource(event.Resource) + collection, ok := c.collections[resourceKind] if !ok { - c.Warningf("Skipping unsupported event %v.", event.Resource.GetKind()) + c.Warningf("Skipping unsupported event %v/%v", + event.Resource.GetKind(), event.Resource.GetSubKind()) return nil } if err := collection.processEvent(ctx, event); err != nil { @@ -1208,3 +1228,23 @@ func (c *Cache) GetDatabaseServers(ctx context.Context, namespace string, opts . defer rg.Release() return rg.presence.GetDatabaseServers(ctx, namespace, opts...) } + +// GetWebSession gets a regular web session. +func (c *Cache) GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + rg, err := c.read() + if err != nil { + return nil, trace.Wrap(err) + } + defer rg.Release() + return rg.webSession.Get(ctx, req) +} + +// GetWebToken gets a web token. +func (c *Cache) GetWebToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + rg, err := c.read() + if err != nil { + return nil, trace.Wrap(err) + } + defer rg.Release() + return rg.webToken.Get(ctx, req) +} diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index 2afabfb912e..7472f7deca1 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -74,6 +74,8 @@ type testPack struct { dynamicAccessS services.DynamicAccess presenceS services.Presence appSessionS services.AppSession + webSessionS types.WebSessionInterface + webTokenS types.WebTokenInterface } func (t *testPack) Close() { @@ -147,6 +149,8 @@ func newPackWithoutCache(dir string, ssetupConfig SetupConfigFn) (*testPack, err p.accessS = local.NewAccessService(p.backend) p.dynamicAccessS = local.NewDynamicAccessService(p.backend) p.appSessionS = local.NewIdentityService(p.backend) + p.webSessionS = local.NewIdentityService(p.backend).WebSessions() + p.webTokenS = local.NewIdentityService(p.backend).WebTokens() return p, nil } @@ -170,6 +174,8 @@ func newPack(dir string, setupConfig func(c Config) Config) (*testPack, error) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, })) @@ -236,6 +242,8 @@ func (s *CacheSuite) TestOnlyRecentInit(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, })) @@ -449,6 +457,8 @@ func (s *CacheSuite) TestCompletenessInit(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, PreferRecent: PreferRecent{ @@ -503,6 +513,8 @@ func (s *CacheSuite) TestCompletenessReset(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, PreferRecent: PreferRecent{ @@ -562,6 +574,8 @@ func (s *CacheSuite) TestTombstones(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, PreferRecent: PreferRecent{ @@ -594,6 +608,8 @@ func (s *CacheSuite) TestTombstones(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, PreferRecent: PreferRecent{ @@ -637,6 +653,8 @@ func (s *CacheSuite) preferRecent(c *check.C) { DynamicAccess: p.dynamicAccessS, Presence: p.presenceS, AppSession: p.appSessionS, + WebSession: p.webSessionS, + WebToken: p.webTokenS, RetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, PreferRecent: PreferRecent{ diff --git a/lib/cache/collections.go b/lib/cache/collections.go index 853c6efbc9e..c84d62f87c4 100644 --- a/lib/cache/collections.go +++ b/lib/cache/collections.go @@ -45,105 +45,119 @@ type collection interface { } // setupCollections returns a mapping of collections -func setupCollections(c *Cache, watches []services.WatchKind) (map[string]collection, error) { - collections := make(map[string]collection, len(watches)) +func setupCollections(c *Cache, watches []services.WatchKind) (map[resourceKind]collection, error) { + collections := make(map[resourceKind]collection, len(watches)) for _, watch := range watches { + resourceKind := resourceKindFromWatchKind(watch) switch watch.Kind { case services.KindCertAuthority: if c.Trust == nil { return nil, trace.BadParameter("missing parameter Trust") } - collections[watch.Kind] = &certAuthority{watch: watch, Cache: c} + collections[resourceKind] = &certAuthority{watch: watch, Cache: c} case services.KindStaticTokens: if c.ClusterConfig == nil { return nil, trace.BadParameter("missing parameter ClusterConfig") } - collections[watch.Kind] = &staticTokens{watch: watch, Cache: c} + collections[resourceKind] = &staticTokens{watch: watch, Cache: c} case services.KindToken: if c.Provisioner == nil { return nil, trace.BadParameter("missing parameter Provisioner") } - collections[watch.Kind] = &provisionToken{watch: watch, Cache: c} + collections[resourceKind] = &provisionToken{watch: watch, Cache: c} case services.KindClusterName: if c.ClusterConfig == nil { return nil, trace.BadParameter("missing parameter ClusterConfig") } - collections[watch.Kind] = &clusterName{watch: watch, Cache: c} + collections[resourceKind] = &clusterName{watch: watch, Cache: c} case services.KindClusterConfig: if c.ClusterConfig == nil { return nil, trace.BadParameter("missing parameter ClusterConfig") } - collections[watch.Kind] = &clusterConfig{watch: watch, Cache: c} + collections[resourceKind] = &clusterConfig{watch: watch, Cache: c} case services.KindUser: if c.Users == nil { return nil, trace.BadParameter("missing parameter Users") } - collections[watch.Kind] = &user{watch: watch, Cache: c} + collections[resourceKind] = &user{watch: watch, Cache: c} case services.KindRole: if c.Access == nil { return nil, trace.BadParameter("missing parameter Access") } - collections[watch.Kind] = &role{watch: watch, Cache: c} + collections[resourceKind] = &role{watch: watch, Cache: c} case services.KindNamespace: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &namespace{watch: watch, Cache: c} + collections[resourceKind] = &namespace{watch: watch, Cache: c} case services.KindNode: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &node{watch: watch, Cache: c} + collections[resourceKind] = &node{watch: watch, Cache: c} case services.KindProxy: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &proxy{watch: watch, Cache: c} + collections[resourceKind] = &proxy{watch: watch, Cache: c} case services.KindAuthServer: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &authServer{watch: watch, Cache: c} + collections[resourceKind] = &authServer{watch: watch, Cache: c} case services.KindReverseTunnel: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &reverseTunnel{watch: watch, Cache: c} + collections[resourceKind] = &reverseTunnel{watch: watch, Cache: c} case services.KindTunnelConnection: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &tunnelConnection{watch: watch, Cache: c} + collections[resourceKind] = &tunnelConnection{watch: watch, Cache: c} case services.KindRemoteCluster: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &remoteCluster{watch: watch, Cache: c} + collections[resourceKind] = &remoteCluster{watch: watch, Cache: c} case services.KindAccessRequest: if c.DynamicAccess == nil { return nil, trace.BadParameter("missing parameter DynamicAccess") } - collections[watch.Kind] = &accessRequest{watch: watch, Cache: c} + collections[resourceKind] = &accessRequest{watch: watch, Cache: c} case services.KindAppServer: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &appServer{watch: watch, Cache: c} + collections[resourceKind] = &appServer{watch: watch, Cache: c} case services.KindWebSession: - if c.AppSession == nil { - return nil, trace.BadParameter("missing parameter AppSession") + switch watch.SubKind { + case services.KindAppSession: + if c.AppSession == nil { + return nil, trace.BadParameter("missing parameter AppSession") + } + collections[resourceKind] = &appSession{watch: watch, Cache: c} + case services.KindWebSession: + if c.WebSession == nil { + return nil, trace.BadParameter("missing parameter WebSession") + } + collections[resourceKind] = &webSession{watch: watch, Cache: c} } - collections[watch.Kind] = &appSession{watch: watch, Cache: c} + case services.KindWebToken: + if c.WebToken == nil { + return nil, trace.BadParameter("missing parameter WebToken") + } + collections[resourceKind] = &webToken{watch: watch, Cache: c} case services.KindKubeService: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &kubeService{watch: watch, Cache: c} + collections[resourceKind] = &kubeService{watch: watch, Cache: c} case types.KindDatabaseServer: if c.Presence == nil { return nil, trace.BadParameter("missing parameter Presence") } - collections[watch.Kind] = &databaseServer{watch: watch, Cache: c} + collections[resourceKind] = &databaseServer{watch: watch, Cache: c} default: return nil, trace.BadParameter("resource %q is not supported", watch.Kind) } @@ -151,6 +165,41 @@ func setupCollections(c *Cache, watches []services.WatchKind) (map[string]collec return collections, nil } +func resourceKindFromWatchKind(wk services.WatchKind) resourceKind { + switch wk.Kind { + case services.KindWebSession: + // Web sessions use subkind to differentiate between + // the types of sessions + return resourceKind{ + kind: wk.Kind, + subkind: wk.SubKind, + } + } + return resourceKind{ + kind: wk.Kind, + } +} + +func resourceKindFromResource(res services.Resource) resourceKind { + switch res.GetKind() { + case services.KindWebSession: + // Web sessions use subkind to differentiate between + // the types of sessions + return resourceKind{ + kind: res.GetKind(), + subkind: res.GetSubKind(), + } + } + return resourceKind{ + kind: res.GetKind(), + } +} + +type resourceKind struct { + kind string + subkind string +} + type accessRequest struct { *Cache watch services.WatchKind @@ -1424,6 +1473,136 @@ func (a *appSession) watchKind() services.WatchKind { return a.watch } +type webSession struct { + *Cache + watch services.WatchKind +} + +func (r *webSession) erase(ctx context.Context) error { + err := r.webSessionCache.DeleteAll(ctx) + if err != nil && !trace.IsNotFound(err) { + return trace.Wrap(err) + } + return nil +} + +func (r *webSession) fetch(ctx context.Context) (apply func(ctx context.Context) error, err error) { + resources, err := r.WebSession.List(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + return func(ctx context.Context) error { + if err := r.erase(ctx); err != nil { + return trace.Wrap(err) + } + for _, resource := range resources { + r.setTTL(resource) + if err := r.webSessionCache.Upsert(ctx, resource); err != nil { + return trace.Wrap(err) + } + } + return nil + }, nil +} + +func (r *webSession) processEvent(ctx context.Context, event services.Event) error { + switch event.Type { + case backend.OpDelete: + err := r.webSessionCache.Delete(ctx, types.DeleteWebSessionRequest{ + SessionID: event.Resource.GetName(), + }) + if err != nil { + // Resource could be missing in the cache expired or not created, if the + // first consumed event is delete. + if !trace.IsNotFound(err) { + r.WithError(err).Warn("Failed to delete resource.") + return trace.Wrap(err) + } + } + case backend.OpPut: + resource, ok := event.Resource.(services.WebSession) + if !ok { + return trace.BadParameter("unexpected type %T", event.Resource) + } + r.setTTL(resource) + if err := r.webSessionCache.Upsert(ctx, resource); err != nil { + return trace.Wrap(err) + } + default: + r.WithField("event", event.Type).Warn("Skipping unsupported event type.") + } + return nil +} + +func (r *webSession) watchKind() services.WatchKind { + return r.watch +} + +type webToken struct { + *Cache + watch services.WatchKind +} + +func (r *webToken) erase(ctx context.Context) error { + err := r.webTokenCache.DeleteAll(ctx) + if err != nil && !trace.IsNotFound(err) { + return trace.Wrap(err) + } + return nil +} + +func (r *webToken) fetch(ctx context.Context) (apply func(ctx context.Context) error, err error) { + resources, err := r.WebToken.List(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + return func(ctx context.Context) error { + if err := r.erase(ctx); err != nil { + return trace.Wrap(err) + } + for _, resource := range resources { + r.setTTL(resource) + if err := r.webTokenCache.Upsert(ctx, resource); err != nil { + return trace.Wrap(err) + } + } + return nil + }, nil +} + +func (r *webToken) processEvent(ctx context.Context, event services.Event) error { + switch event.Type { + case backend.OpDelete: + err := r.webTokenCache.Delete(ctx, types.DeleteWebTokenRequest{ + Token: event.Resource.GetName(), + }) + if err != nil { + // Resource could be missing in the cache expired or not created, if the + // first consumed event is delete. + if !trace.IsNotFound(err) { + r.WithError(err).Warn("Failed to delete resource.") + return trace.Wrap(err) + } + } + case backend.OpPut: + resource, ok := event.Resource.(types.WebToken) + if !ok { + return trace.BadParameter("unexpected type %T", event.Resource) + } + r.setTTL(resource) + if err := r.webTokenCache.Upsert(ctx, resource); err != nil { + return trace.Wrap(err) + } + default: + r.WithField("event", event.Type).Warn("Skipping unsupported event type.") + } + return nil +} + +func (r *webToken) watchKind() services.WatchKind { + return r.watch +} + type kubeService struct { *Cache watch services.WatchKind diff --git a/lib/defaults/defaults.go b/lib/defaults/defaults.go index d36ac08593f..4e1a3f7ed3b 100644 --- a/lib/defaults/defaults.go +++ b/lib/defaults/defaults.go @@ -422,13 +422,12 @@ const ( ) const ( - // MinCertDuration specifies minimum duration of validity of issued cert + // MinCertDuration specifies minimum duration of validity of issued certificate MinCertDuration = time.Minute - // MaxCertDuration limits maximum duration of validity of issued cert + // MaxCertDuration limits maximum duration of validity of issued certificate MaxCertDuration = defaults.MaxCertDuration - // CertDuration is a default certificate duration - // 12 is default as it' longer than average working day (I hope so) - CertDuration = 12 * time.Hour + // CertDuration is a default certificate duration. + CertDuration = defaults.CertDuration // RotationGracePeriod is a default rotation period for graceful // certificate rotations, by default to set to maximum allowed user // cert duration diff --git a/lib/reversetunnel/srv.go b/lib/reversetunnel/srv.go index 585c5cb46ec..e29a69a3127 100644 --- a/lib/reversetunnel/srv.go +++ b/lib/reversetunnel/srv.go @@ -69,7 +69,7 @@ func init() { // server is a "reverse tunnel server". it exposes the cluster capabilities // (like access to a cluster's auth) to remote trusted clients -// (also known as 'reverse tunnel agents'. +// (also known as 'reverse tunnel agents'). type server struct { sync.RWMutex Config diff --git a/lib/service/service.go b/lib/service/service.go index 8cfbbc0285f..3e3c4b88249 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -1493,6 +1493,8 @@ func (process *TeleportProcess) newAccessCache(cfg accessCacheConfig) (*cache.Ca DynamicAccess: cfg.services, Presence: cfg.services, AppSession: cfg.services, + WebSession: cfg.services.WebSessions(), + WebToken: cfg.services.WebTokens(), Component: teleport.Component(append(cfg.cacheName, process.id, teleport.ComponentCache)...), MetricComponent: teleport.Component(append(cfg.cacheName, teleport.ComponentCache)...), })) @@ -2458,13 +2460,19 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { if len(cfg.Proxy.Kube.PublicAddrs) > 0 { proxySettings.Kube.PublicAddr = cfg.Proxy.Kube.PublicAddrs[0].String() } + var fs http.FileSystem + if !process.Config.Proxy.DisableWebInterface { + fs, err = newHTTPFileSystem() + if err != nil { + return trace.Wrap(err) + } + } webHandler, err = web.NewHandler( web.Config{ Proxy: tsrv, AuthServers: cfg.AuthServers[0], DomainName: cfg.Hostname, ProxyClient: conn.Client, - DisableUI: process.Config.Proxy.DisableWebInterface, ProxySSHAddr: cfg.Proxy.SSHAddr, ProxyWebAddr: cfg.Proxy.WebAddr, ProxySettings: proxySettings, @@ -2474,6 +2482,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { Emitter: streamEmitter, HostUUID: process.Config.HostUUID, Context: process.ExitContext(), + StaticFS: fs, }) if err != nil { return trace.Wrap(err) @@ -3308,3 +3317,28 @@ func findPublicAddr(authClient auth.AccessPoint, a App) (string, error) { } return fmt.Sprintf("%v.%v", a.Name, cn.GetClusterName()), nil } + +// newHTTPFileSystem creates a new HTTP file system for the web handler. +// It uses external configuration to make the decision +func newHTTPFileSystem() (http.FileSystem, error) { + if !isDebugMode() { + fs, err := web.NewStaticFileSystem() + if err != nil { + return nil, trace.Wrap(err) + } + return fs, nil + } + // Use debug HTTP file system with default assets path + fs, err := web.NewDebugFileSystem("") + if err != nil { + return nil, trace.Wrap(err) + } + return fs, nil +} + +// isDebugMode determines if teleport is running in a "debug" mode. +// It looks at DEBUG environment variable +func isDebugMode() bool { + v, _ := strconv.ParseBool(os.Getenv(teleport.DebugEnvVar)) + return v +} diff --git a/lib/service/service_test.go b/lib/service/service_test.go index 62943d29b49..b116052e641 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -51,6 +51,18 @@ func (s *ServiceTestSuite) SetUpSuite(c *check.C) { utils.InitLoggerForTests(testing.Verbose()) } +func (s *ServiceTestSuite) TestDebugModeEnv(c *check.C) { + c.Assert(isDebugMode(), check.Equals, false) + os.Setenv(teleport.DebugEnvVar, "no") + c.Assert(isDebugMode(), check.Equals, false) + os.Setenv(teleport.DebugEnvVar, "0") + c.Assert(isDebugMode(), check.Equals, false) + os.Setenv(teleport.DebugEnvVar, "1") + c.Assert(isDebugMode(), check.Equals, true) + os.Setenv(teleport.DebugEnvVar, "true") + c.Assert(isDebugMode(), check.Equals, true) +} + func (s *ServiceTestSuite) TestSelfSignedHTTPS(c *check.C) { fileExists := func(fp string) bool { _, err := os.Stat(fp) diff --git a/lib/services/identity.go b/lib/services/identity.go index 25b2aa81057..8d6c292a348 100644 --- a/lib/services/identity.go +++ b/lib/services/identity.go @@ -207,16 +207,10 @@ type Identity interface { // GetResetPasswordTokenSecrets returns token secrets GetResetPasswordTokenSecrets(ctx context.Context, tokenID string) (ResetPasswordTokenSecrets, error) - // GetWebSession returns a web session state for a given user and session id - GetWebSession(user, sid string) (WebSession, error) + types.WebSessionsGetter + types.WebTokensGetter - // UpsertWebSession updates or inserts a web session for a user and session - UpsertWebSession(user, sid string, session WebSession) error - - // DeleteWebSession deletes web session from the storage - DeleteWebSession(user, sid string) error - - // AppSession defines session features. + // AppSession defines application session features. AppSession } diff --git a/lib/services/local/events.go b/lib/services/local/events.go index 5f167061365..0bec5d685f2 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -27,6 +27,7 @@ import ( "github.com/gravitational/teleport/lib/services" "github.com/gravitational/trace" + "github.com/jonboulle/clockwork" "github.com/sirupsen/logrus" ) @@ -92,7 +93,16 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch services.Watch) (s case services.KindAppServer: parser = newAppServerParser() case services.KindWebSession: - parser = newAppSessionParser() + switch kind.SubKind { + case services.KindAppSession: + parser = newAppSessionParser() + case services.KindWebSession: + parser = newWebSessionParser() + default: + return nil, trace.BadParameter("watcher on object subkind %q is not supported", kind.SubKind) + } + case services.KindWebToken: + parser = newWebTokenParser() case services.KindRemoteCluster: parser = newRemoteClusterParser() case services.KindKubeService: @@ -100,7 +110,7 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch services.Watch) (s case types.KindDatabaseServer: parser = newDatabaseServerParser() default: - return nil, trace.BadParameter("watcher on object kind %v is not supported", kind) + return nil, trace.BadParameter("watcher on object kind %q is not supported", kind.Kind) } prefixes = append(prefixes, parser.prefix()) parsers = append(parsers, parser) @@ -685,17 +695,34 @@ func (p *appServerParser) parse(event backend.Event) (services.Resource, error) func newAppSessionParser() *webSessionParser { return &webSessionParser{ baseParser: baseParser{matchPrefix: backend.Key(appsPrefix, sessionsPrefix)}, + hdr: services.ResourceHeader{ + Kind: services.KindWebSession, + SubKind: services.KindAppSession, + Version: services.V2, + }, + } +} + +func newWebSessionParser() *webSessionParser { + return &webSessionParser{ + baseParser: baseParser{matchPrefix: backend.Key(webPrefix, sessionsPrefix)}, + hdr: services.ResourceHeader{ + Kind: services.KindWebSession, + SubKind: services.KindWebSession, + Version: services.V2, + }, } } type webSessionParser struct { baseParser + hdr services.ResourceHeader } func (p *webSessionParser) parse(event backend.Event) (services.Resource, error) { switch event.Type { case backend.OpDelete: - return resourceHeader(event, services.KindWebSession, services.V2, 0) + return resourceHeaderWithTemplate(event, p.hdr, 0) case backend.OpPut: resource, err := services.UnmarshalWebSession(event.Item.Value, services.WithResourceID(event.Item.ID), @@ -710,6 +737,34 @@ func (p *webSessionParser) parse(event backend.Event) (services.Resource, error) } } +func newWebTokenParser() *webTokenParser { + return &webTokenParser{ + baseParser: baseParser{matchPrefix: backend.Key(webPrefix, tokensPrefix)}, + } +} + +type webTokenParser struct { + baseParser +} + +func (p *webTokenParser) parse(event backend.Event) (services.Resource, error) { + switch event.Type { + case backend.OpDelete: + return resourceHeader(event, services.KindWebToken, services.V1, 0) + case backend.OpPut: + resource, err := services.UnmarshalWebToken(event.Item.Value, + services.WithResourceID(event.Item.ID), + services.WithExpires(event.Item.Expires), + ) + if err != nil { + return nil, trace.Wrap(err) + } + return resource, nil + default: + return nil, trace.BadParameter("event %v is not supported", event.Type) + } +} + func newKubeServiceParser() *kubeServiceParser { return &kubeServiceParser{ baseParser: baseParser{matchPrefix: backend.Key(kubeServicesPrefix)}, @@ -832,6 +887,75 @@ func resourceHeader(event backend.Event, kind, version string, offset int) (serv }, nil } +func resourceHeaderWithTemplate(event backend.Event, hdr services.ResourceHeader, offset int) (services.Resource, error) { + name, err := base(event.Item.Key, offset) + if err != nil { + return nil, trace.Wrap(err) + } + return &services.ResourceHeader{ + Kind: hdr.Kind, + SubKind: hdr.SubKind, + Version: hdr.Version, + Metadata: services.Metadata{ + Name: string(name), + Namespace: defaults.Namespace, + }, + }, nil +} + +// WaitForEvent waits for the event matched by the specified event matcher in the given watcher. +func WaitForEvent(ctx context.Context, watcher services.Watcher, m EventMatcher, clock clockwork.Clock) (services.Resource, error) { + tick := clock.NewTicker(defaults.WebHeadersTimeout) + defer tick.Stop() + + select { + case event := <-watcher.Events(): + if event.Type != backend.OpInit { + return nil, trace.BadParameter("expected init event, got %v instead", event.Type) + } + case <-watcher.Done(): + // Watcher closed, probably due to a network error. + return nil, trace.ConnectionProblem(watcher.Error(), "watcher is closed") + case <-tick.Chan(): + return nil, trace.LimitExceeded("timed out waiting for initialize event") + } + + for { + select { + case event := <-watcher.Events(): + res, err := m.Match(event) + if err == nil { + return res, nil + } + if !trace.IsCompareFailed(err) { + logrus.WithError(err).Debug("Failed to match event.") + } + case <-watcher.Done(): + // Watcher closed, probably due to a network error. + return nil, trace.ConnectionProblem(watcher.Error(), "watcher is closed") + case <-tick.Chan(): + return nil, trace.LimitExceeded("timed out waiting for event") + } + } +} + +// Match matches the specified resource event by applying itself +func (r EventMatcherFunc) Match(event services.Event) (services.Resource, error) { + return r(event) +} + +// EventMatcherFunc matches the specified resource event. +// Implements EventMatcher +type EventMatcherFunc func(services.Event) (services.Resource, error) + +// EventMatcher matches a specific resource event +type EventMatcher interface { + // Match matches the specified event. + // Returns the matched resource if successful. + // Returns trace.CompareFailedError for no match. + Match(services.Event) (services.Resource, error) +} + // base returns last element delimited by separator, index is // is an index of the key part to get counting from the end func base(key []byte, offset int) ([]byte, error) { diff --git a/lib/services/local/session.go b/lib/services/local/session.go index c9dd373af1c..9d76fa98f0b 100644 --- a/lib/services/local/session.go +++ b/lib/services/local/session.go @@ -19,14 +19,16 @@ package local import ( "context" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/trace" + "github.com/sirupsen/logrus" ) // GetAppSession gets an application web session. -func (s *IdentityService) GetAppSession(ctx context.Context, req services.GetAppSessionRequest) (services.WebSession, error) { +func (s *IdentityService) GetAppSession(ctx context.Context, req types.GetAppSessionRequest) (types.WebSession, error) { if err := req.Check(); err != nil { return nil, trace.Wrap(err) } @@ -43,14 +45,14 @@ func (s *IdentityService) GetAppSession(ctx context.Context, req services.GetApp } // GetAppSessions gets all application web sessions. -func (s *IdentityService) GetAppSessions(ctx context.Context) ([]services.WebSession, error) { +func (s *IdentityService) GetAppSessions(ctx context.Context) ([]types.WebSession, error) { startKey := backend.Key(appsPrefix, sessionsPrefix) result, err := s.GetRange(ctx, startKey, backend.RangeEnd(startKey), backend.NoLimit) if err != nil { return nil, trace.Wrap(err) } - out := make([]services.WebSession, len(result.Items)) + out := make([]types.WebSession, len(result.Items)) for i, item := range result.Items { session, err := services.UnmarshalWebSession(item.Value, services.SkipValidation()) if err != nil { @@ -95,3 +97,226 @@ func (s *IdentityService) DeleteAllAppSessions(ctx context.Context) error { } return nil } + +// WebSessions returns the web sessions manager. +func (s *IdentityService) WebSessions() types.WebSessionInterface { + return &webSessions{backend: s.Backend, log: s.log} +} + +// Get returns the web session state described with req. +func (r *webSessions) Get(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + if err := req.Check(); err != nil { + return nil, trace.Wrap(err) + } + item, err := r.backend.Get(ctx, webSessionKey(req.SessionID)) + if err != nil { + return nil, trace.Wrap(err) + } + session, err := services.UnmarshalWebSession(item.Value, services.SkipValidation()) + if err != nil && !trace.IsNotFound(err) { + return nil, trace.Wrap(err) + } + if session != nil { + return session, nil + } + // DELETE IN 7.x: + // Return web sessions from a legacy path under /web/users//sessions/ + return getLegacyWebSession(ctx, r.backend, req.User, req.SessionID) +} + +// List gets all regular web sessions. +func (r *webSessions) List(ctx context.Context) (out []types.WebSession, err error) { + key := backend.Key(webPrefix, sessionsPrefix) + result, err := r.backend.GetRange(ctx, key, backend.RangeEnd(key), backend.NoLimit) + if err != nil { + return nil, trace.Wrap(err) + } + for _, item := range result.Items { + session, err := services.UnmarshalWebSession(item.Value, services.SkipValidation()) + if err != nil { + return nil, trace.Wrap(err) + } + out = append(out, session) + } + // DELETE IN 7.x: + // Return web sessions from a legacy path under /web/users//sessions/ + legacySessions, err := r.listLegacySessions(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + return append(out, legacySessions...), nil +} + +// Upsert updates the existing or inserts a new web session. +func (r *webSessions) Upsert(ctx context.Context, session types.WebSession) error { + value, err := services.MarshalWebSession(session) + if err != nil { + return trace.Wrap(err) + } + sessionMetadata := session.GetMetadata() + item := backend.Item{ + Key: webSessionKey(session.GetName()), + Value: value, + Expires: backend.EarliestExpiry(session.GetBearerTokenExpiryTime(), sessionMetadata.Expiry()), + } + _, err = r.backend.Put(ctx, item) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// Delete deletes the web session specified with req from the storage. +func (r *webSessions) Delete(ctx context.Context, req types.DeleteWebSessionRequest) error { + if err := req.Check(); err != nil { + return trace.Wrap(err) + } + return trace.Wrap(r.backend.Delete(ctx, webSessionKey(req.SessionID))) +} + +// DeleteAll removes all regular web sessions. +func (r *webSessions) DeleteAll(ctx context.Context) error { + startKey := backend.Key(webPrefix, sessionsPrefix) + return trace.Wrap(r.backend.DeleteRange(ctx, startKey, backend.RangeEnd(startKey))) +} + +// DELETE IN 7.x. +// listLegacySessions lists web sessions under a legacy path /web/users//sessions/ +func (r *webSessions) listLegacySessions(ctx context.Context) ([]types.WebSession, error) { + startKey := backend.Key(webPrefix, usersPrefix) + result, err := r.backend.GetRange(ctx, startKey, backend.RangeEnd(startKey), backend.NoLimit) + if err != nil { + return nil, trace.Wrap(err) + } + out := make([]types.WebSession, 0, len(result.Items)) + for _, item := range result.Items { + suffix, _, err := baseTwoKeys(item.Key) + if err != nil && trace.IsNotFound(err) { + return nil, trace.Wrap(err) + } + if suffix != sessionsPrefix { + continue + } + session, err := services.UnmarshalWebSession(item.Value, services.SkipValidation()) + if err != nil { + return nil, trace.Wrap(err) + } + out = append(out, session) + } + return out, nil +} + +type webSessions struct { + backend backend.Backend + log logrus.FieldLogger +} + +// WebTokens returns the web token manager. +func (s *IdentityService) WebTokens() types.WebTokenInterface { + return &webTokens{backend: s.Backend, log: s.log} +} + +// Get returns the web token described with req. +func (r *webTokens) Get(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + if err := req.Check(); err != nil { + return nil, trace.Wrap(err) + } + item, err := r.backend.Get(ctx, webTokenKey(req.Token)) + if err != nil { + return nil, trace.Wrap(err) + } + token, err := services.UnmarshalWebToken(item.Value, services.SkipValidation()) + if err != nil { + return nil, trace.Wrap(err) + } + return token, nil +} + +// List gets all web tokens. +func (r *webTokens) List(ctx context.Context) (out []types.WebToken, err error) { + key := backend.Key(webPrefix, tokensPrefix) + result, err := r.backend.GetRange(ctx, key, backend.RangeEnd(key), backend.NoLimit) + if err != nil { + return nil, trace.Wrap(err) + } + for _, item := range result.Items { + token, err := services.UnmarshalWebToken(item.Value, services.SkipValidation()) + if err != nil { + return nil, trace.Wrap(err) + } + out = append(out, token) + } + return out, nil +} + +// Upsert updates the existing or inserts a new web token. +func (r *webTokens) Upsert(ctx context.Context, token types.WebToken) error { + bytes, err := services.MarshalWebToken(token, services.WithVersion(services.V3)) + if err != nil { + return trace.Wrap(err) + } + metadata := token.GetMetadata() + item := backend.Item{ + Key: webTokenKey(token.GetToken()), + Value: bytes, + Expires: metadata.Expiry(), + } + _, err = r.backend.Put(ctx, item) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// Delete deletes the web token specified with req from the storage. +func (r *webTokens) Delete(ctx context.Context, req types.DeleteWebTokenRequest) error { + if err := req.Check(); err != nil { + return trace.Wrap(err) + } + return trace.Wrap(r.backend.Delete(ctx, webTokenKey(req.Token))) +} + +// DeleteAll removes all web tokens. +func (r *webTokens) DeleteAll(ctx context.Context) error { + startKey := backend.Key(webPrefix, tokensPrefix) + if err := r.backend.DeleteRange(ctx, startKey, backend.RangeEnd(startKey)); err != nil { + return trace.Wrap(err) + } + return nil +} + +type webTokens struct { + backend backend.Backend + log logrus.FieldLogger +} + +// DELETE in 7.x. +// getLegacySession returns the web session for the specified user/sessionID +// under a legacy path /web/users//sessions/ +func getLegacyWebSession(ctx context.Context, backend backend.Backend, user, sessionID string) (types.WebSession, error) { + item, err := backend.Get(ctx, legacyWebSessionKey(user, sessionID)) + if err != nil { + return nil, trace.Wrap(err) + } + session, err := services.UnmarshalWebSession(item.Value, services.SkipValidation()) + if err != nil { + return nil, trace.Wrap(err) + } + // this is for backwards compatibility to ensure we + // always have these values + session.SetUser(user) + session.SetName(sessionID) + return session, nil +} + +func webSessionKey(sessionID string) (key []byte) { + return backend.Key(webPrefix, sessionsPrefix, sessionID) +} + +func webTokenKey(token string) (key []byte) { + return backend.Key(webPrefix, tokensPrefix, token) +} + +func legacyWebSessionKey(user, sessionID string) (key []byte) { + return backend.Key(webPrefix, usersPrefix, user, sessionsPrefix, sessionID) +} diff --git a/lib/services/local/users.go b/lib/services/local/users.go index a421394fbf5..9140f6881b0 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -34,18 +34,21 @@ import ( "github.com/gokyle/hotp" "github.com/gravitational/trace" "github.com/pborman/uuid" + "github.com/sirupsen/logrus" ) // IdentityService is responsible for managing web users and currently // user accounts as well type IdentityService struct { backend.Backend + log logrus.FieldLogger } // NewIdentityService returns a new instance of IdentityService object func NewIdentityService(backend backend.Backend) *IdentityService { return &IdentityService{ Backend: backend, + log: logrus.WithField(trace.Component, "identity"), } } @@ -450,26 +453,6 @@ func (s *IdentityService) DeleteUsedTOTPToken(user string) error { return s.Delete(context.TODO(), backend.Key(webPrefix, usersPrefix, user, usedTOTPPrefix)) } -// UpsertWebSession updates or inserts a web session for a user and session id -// the session will be created with bearer token expiry time TTL, because -// it is expected to be extended by the client before then -func (s *IdentityService) UpsertWebSession(user, sid string, session services.WebSession) error { - session.SetUser(user) - session.SetName(sid) - value, err := services.MarshalWebSession(session) - if err != nil { - return trace.Wrap(err) - } - sessionMetadata := session.GetMetadata() - item := backend.Item{ - Key: backend.Key(webPrefix, usersPrefix, user, sessionsPrefix, sid), - Value: value, - Expires: backend.EarliestExpiry(session.GetBearerTokenExpiryTime(), sessionMetadata.Expiry()), - } - _, err = s.Put(context.TODO(), item) - return trace.Wrap(err) -} - // AddUserLoginAttempt logs user login attempt func (s *IdentityService) AddUserLoginAttempt(user string, attempt services.LoginAttempt, ttl time.Duration) error { if err := attempt.Check(); err != nil { @@ -521,41 +504,6 @@ func (s *IdentityService) DeleteUserLoginAttempts(user string) error { return nil } -// GetWebSession returns a web session state for a given user and session id -func (s *IdentityService) GetWebSession(user, sid string) (services.WebSession, error) { - if user == "" { - return nil, trace.BadParameter("missing username") - } - if sid == "" { - return nil, trace.BadParameter("missing session id") - } - item, err := s.Get(context.TODO(), backend.Key(webPrefix, usersPrefix, user, sessionsPrefix, sid)) - if err != nil { - return nil, trace.Wrap(err) - } - session, err := services.UnmarshalWebSession(item.Value) - if err != nil { - return nil, trace.Wrap(err) - } - // this is for backwards compatibility to ensure we - // always have these values - session.SetUser(user) - session.SetName(sid) - return session, nil -} - -// DeleteWebSession deletes web session from the storage -func (s *IdentityService) DeleteWebSession(user, sid string) error { - if user == "" { - return trace.BadParameter("missing username") - } - if sid == "" { - return trace.BadParameter("missing session id") - } - err := s.Delete(context.TODO(), backend.Key(webPrefix, usersPrefix, user, sessionsPrefix, sid)) - return trace.Wrap(err) -} - // UpsertPassword upserts new password hash into a backend. func (s *IdentityService) UpsertPassword(user string, password []byte) error { if user == "" { diff --git a/lib/services/resource.go b/lib/services/resource.go index d8c38fd34d3..93d48ad5bc1 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -95,7 +95,7 @@ func WithExpires(expires time.Time) MarshalOption { func WithVersion(v string) MarshalOption { return func(c *MarshalConfig) error { switch v { - case V1, V2: + case V1, V2, V3: c.Version = v return nil default: diff --git a/lib/services/services.go b/lib/services/services.go index c0e6b8ba28c..48680e528ae 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -16,6 +16,8 @@ limitations under the License. package services +import "github.com/gravitational/teleport/api/types" + // Services collects all services type Services interface { UsersService @@ -27,4 +29,6 @@ type Services interface { DynamicAccess Presence AppSession + types.WebSessionsGetter + types.WebTokensGetter } diff --git a/lib/services/session.go b/lib/services/session.go index 409dc230a84..655b7df41dd 100644 --- a/lib/services/session.go +++ b/lib/services/session.go @@ -20,7 +20,9 @@ import ( "encoding/json" "fmt" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/trace" ) @@ -57,7 +59,7 @@ func ExtendWebSession(ws WebSession) (WebSession, error) { } // UnmarshalWebSession unmarshals the WebSession resource from JSON. -func UnmarshalWebSession(bytes []byte, opts ...MarshalOption) (WebSession, error) { +func UnmarshalWebSession(bytes []byte, opts ...MarshalOption) (types.WebSession, error) { cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -70,7 +72,7 @@ func UnmarshalWebSession(bytes []byte, opts ...MarshalOption) (WebSession, error } switch h.Version { case V2: - var ws WebSessionV2 + var ws types.WebSessionV2 if err := utils.UnmarshalWithSchema(GetWebSessionSchema(), &ws, bytes); err != nil { return nil, trace.BadParameter(err.Error()) } @@ -94,7 +96,7 @@ func UnmarshalWebSession(bytes []byte, opts ...MarshalOption) (WebSession, error } // MarshalWebSession marshals the WebSession resource to JSON. -func MarshalWebSession(ws WebSession, opts ...MarshalOption) ([]byte, error) { +func MarshalWebSession(ws types.WebSession, opts ...MarshalOption) ([]byte, error) { cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -114,3 +116,77 @@ func MarshalWebSession(ws WebSession, opts ...MarshalOption) ([]byte, error) { return nil, trace.BadParameter("unrecognized web session version %T", ws) } } + +// MarshalWebToken serializes the web token as JSON-encoded payload +func MarshalWebToken(token types.WebToken, opts ...MarshalOption) ([]byte, error) { + cfg, err := CollectOptions(opts) + if err != nil { + return nil, trace.Wrap(err) + } + version := cfg.GetVersion() + switch version { + case V3: + value, ok := token.(*types.WebTokenV3) + if !ok { + return nil, trace.BadParameter("don't know how to marshal web token %v", token) + } + if !cfg.PreserveResourceID { + // avoid modifying the original object + // to prevent unexpected data races + copy := *value + copy.SetResourceID(0) + value = © + } + return utils.FastMarshal(value) + default: + return nil, trace.BadParameter("version %v is not supported", version) + } +} + +// UnmarshalWebToken interprets bytes as JSON-encoded web token value +func UnmarshalWebToken(bytes []byte, opts ...MarshalOption) (types.WebToken, error) { + config, err := CollectOptions(opts) + if err != nil { + return nil, trace.Wrap(err) + } + var hdr ResourceHeader + err = json.Unmarshal(bytes, &hdr) + if err != nil { + return nil, trace.Wrap(err) + } + switch hdr.Version { + case V3: + var token types.WebTokenV3 + if err := utils.UnmarshalWithSchema(GetWebTokenSchema(), &token, bytes); err != nil { + return nil, trace.BadParameter("invalid web token: %v", err.Error()) + } + if err := token.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + if config.ID != 0 { + token.SetResourceID(config.ID) + } + if !config.Expires.IsZero() { + token.Metadata.SetExpiry(config.Expires) + } + utils.UTC(token.Metadata.Expires) + return &token, nil + } + return nil, trace.BadParameter("web token resource version %v is not supported", hdr.Version) +} + +// GetWebTokenSchema returns JSON schema for the web token resource +func GetWebTokenSchema() string { + return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, WebTokenSpecV3Schema, "") +} + +// WebTokenSpecV3Schema is JSON schema for the web token V3 +const WebTokenSpecV3Schema = `{ + "type": "object", + "additionalProperties": false, + "required": ["token", "user"], + "properties": { + "user": {"type": "string"}, + "token": {"type": "string"} + } +}` diff --git a/lib/services/suite/suite.go b/lib/services/suite/suite.go index 09653d0ac0f..6acad4cfcb2 100644 --- a/lib/services/suite/suite.go +++ b/lib/services/suite/suite.go @@ -31,6 +31,7 @@ import ( "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth/u2f" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/defaults" @@ -547,39 +548,45 @@ func (s *ServicesTestSuite) PasswordHashCRUD(c *check.C) { } func (s *ServicesTestSuite) WebSessionCRUD(c *check.C) { - _, err := s.WebS.GetWebSession("user1", "sid1") + req := types.GetWebSessionRequest{User: "user1", SessionID: "sid1"} + _, err := s.WebS.WebSessions().Get(context.TODO(), req) c.Assert(trace.IsNotFound(err), check.Equals, true, check.Commentf("%#v", err)) dt := s.Clock.Now().Add(1 * time.Minute) - ws := services.NewWebSession("sid1", services.KindWebSession, services.KindWebSession, - services.WebSessionSpecV2{ + ws := types.NewWebSession("sid1", services.KindWebSession, services.KindWebSession, + types.WebSessionSpecV2{ + User: "user1", Pub: []byte("pub123"), Priv: []byte("priv123"), Expires: dt, }) - err = s.WebS.UpsertWebSession("user1", "sid1", ws) + err = s.WebS.WebSessions().Upsert(context.TODO(), ws) c.Assert(err, check.IsNil) - out, err := s.WebS.GetWebSession("user1", "sid1") + out, err := s.WebS.WebSessions().Get(context.TODO(), req) c.Assert(err, check.IsNil) c.Assert(out, check.DeepEquals, ws) - ws1 := services.NewWebSession("sid1", services.KindWebSession, services.KindWebSession, - services.WebSessionSpecV2{ + ws1 := types.NewWebSession("sid1", services.KindWebSession, services.KindWebSession, + types.WebSessionSpecV2{ + User: "user1", Pub: []byte("pub321"), Priv: []byte("priv321"), Expires: dt, }) - err = s.WebS.UpsertWebSession("user1", "sid1", ws1) + err = s.WebS.WebSessions().Upsert(context.TODO(), ws1) c.Assert(err, check.IsNil) - out2, err := s.WebS.GetWebSession("user1", "sid1") + out2, err := s.WebS.WebSessions().Get(context.TODO(), req) c.Assert(err, check.IsNil) c.Assert(out2, check.DeepEquals, ws1) - c.Assert(s.WebS.DeleteWebSession("user1", "sid1"), check.IsNil) + c.Assert(s.WebS.WebSessions().Delete(context.TODO(), types.DeleteWebSessionRequest{ + User: req.User, + SessionID: req.SessionID, + }), check.IsNil) - _, err = s.WebS.GetWebSession("user1", "sid1") + _, err = s.WebS.WebSessions().Get(context.TODO(), req) fixtures.ExpectNotFound(c, err) } diff --git a/lib/services/types.go b/lib/services/types.go index 1eece6af603..fd6bbbb7979 100644 --- a/lib/services/types.go +++ b/lib/services/types.go @@ -467,6 +467,7 @@ const ( KindSession = types.KindSession KindSSHSession = types.KindSSHSession KindWebSession = types.KindWebSession + KindWebToken = types.KindWebToken KindAppSession = types.KindAppSession KindEvent = types.KindEvent KindAuthServer = types.KindAuthServer diff --git a/lib/srv/heartbeat.go b/lib/srv/heartbeat.go index 90f7a0ee2b7..e237bb83dda 100644 --- a/lib/srv/heartbeat.go +++ b/lib/srv/heartbeat.go @@ -136,7 +136,7 @@ func NewHeartbeat(cfg HeartbeatConfig) (*Heartbeat, error) { Entry: log.WithFields(log.Fields{ trace.Component: teleport.Component(cfg.Component, "beat"), }), - checkTicker: time.NewTicker(cfg.CheckPeriod), + checkTicker: cfg.Clock.NewTicker(cfg.CheckPeriod), announceC: make(chan struct{}, 1), sendC: make(chan struct{}, 1), } @@ -237,7 +237,7 @@ type Heartbeat struct { nextKeepAlive time.Time // checkTicker is a ticker for state transitions // during which different checks are performed - checkTicker *time.Ticker + checkTicker clockwork.Ticker // keepAliver sends keep alive updates keepAliver services.KeepAliver // announceC is event receives an event @@ -262,7 +262,7 @@ func (h *Heartbeat) Run() error { } h.OnHeartbeat(err) select { - case <-h.checkTicker.C: + case <-h.checkTicker.Chan(): case <-h.sendC: h.Debugf("Asked check out of cycle") case <-h.cancelCtx.Done(): diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index e4a61e3675a..e32a9d1585e 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -21,7 +21,6 @@ package web import ( "compress/gzip" "context" - "crypto/subtle" "encoding/base64" "encoding/json" "fmt" @@ -37,6 +36,7 @@ import ( "time" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/u2f" "github.com/gravitational/teleport/lib/client" @@ -111,8 +111,6 @@ type Config struct { DomainName string // ProxyClient is a client that authenticated as proxy ProxyClient auth.ClientI - // DisableUI allows to turn off serving web based UI - DisableUI bool // ProxySSHAddr points to the SSH address of the proxy ProxySSHAddr utils.NetAddr // ProxyWebAddr points to the web (HTTPS) address of the proxy @@ -139,6 +137,15 @@ type Config struct { // Context is used to signal process exit. Context context.Context + + // StaticFS optionally specifies the HTTP file system to use. + // Enables web UI if set. + StaticFS http.FileSystem + + // cachedSessionLingeringThreshold specifies the time the session will linger + // in the cache before getting purged after it has expired. + // Defaults to cachedSessionLingeringThreshold if unspecified. + cachedSessionLingeringThreshold *time.Duration } type RewritingHandler struct { @@ -191,11 +198,18 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { } } - auth, err := newSessionCache(&sessionCache{ - proxyClient: cfg.ProxyClient, - authServers: []utils.NetAddr{cfg.AuthServers}, - cipherSuites: cfg.CipherSuites, - clock: h.clock, + sessionLingeringThreshold := cachedSessionLingeringThreshold + if cfg.cachedSessionLingeringThreshold != nil { + sessionLingeringThreshold = *cfg.cachedSessionLingeringThreshold + } + + auth, err := newSessionCache(sessionCacheOptions{ + proxyClient: cfg.ProxyClient, + accessPoint: cfg.AccessPoint, + servers: []utils.NetAddr{cfg.AuthServers}, + cipherSuites: cfg.CipherSuites, + clock: h.clock, + sessionLingeringThreshold: sessionLingeringThreshold, }) if err != nil { return nil, trace.Wrap(err) @@ -309,16 +323,9 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { h.POST("/webapi/host/credentials", httplib.MakeHandler(h.hostCredentials)) // if Web UI is enabled, check the assets dir: - var ( - indexPage *template.Template - staticFS http.FileSystem - ) - if !cfg.DisableUI { - staticFS, err = NewStaticFileSystem(isDebugMode()) - if err != nil { - return nil, trace.Wrap(err) - } - index, err := staticFS.Open("/index.html") + var indexPage *template.Template + if cfg.StaticFS != nil { + index, err := cfg.StaticFS.Open("/index.html") if err != nil { h.log.WithError(err).Error("Failed to open index file.") return nil, trace.Wrap(err) @@ -344,7 +351,7 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { } // request is going to the web UI - if cfg.DisableUI { + if cfg.StaticFS == nil { w.WriteHeader(http.StatusNotImplemented) return } @@ -358,7 +365,7 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { // serve Web UI: if strings.HasPrefix(r.URL.Path, "/web/app") { httplib.SetStaticFileHeaders(w.Header()) - http.StripPrefix("/web", http.FileServer(staticFS)).ServeHTTP(w, r) + http.StripPrefix("/web", http.FileServer(cfg.StaticFS)).ServeHTTP(w, r) } else if strings.HasPrefix(r.URL.Path, "/web/") || r.URL.Path == "/web" { csrfToken, err := csrf.AddCSRFProtection(w, r) if err != nil { @@ -374,9 +381,9 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { ctx, err := h.AuthenticateRequest(w, r, false) if err == nil { - re, err := NewSessionResponse(ctx) + resp, err := newSessionResponse(ctx) if err == nil { - out, err := json.Marshal(re) + out, err := json.Marshal(resp) if err == nil { session.Session = base64.StdEncoding.EncodeToString(out) } @@ -946,7 +953,7 @@ func (h *Handler) githubCallback(w http.ResponseWriter, r *http.Request, p httpr return nil, trace.AccessDenied("access denied") } logger.Infof("Callback is redirecting to web browser.") - err = SetSession(w, response.Username, response.Session.GetName()) + err = SetSessionCookie(w, response.Username, response.Session.GetName()) if err != nil { return nil, trace.Wrap(err) } @@ -1028,7 +1035,7 @@ func (h *Handler) oidcCallback(w http.ResponseWriter, r *http.Request, p httprou } logger.Info("Callback redirecting to web browser.") - if err := SetSession(w, response.Username, response.Session.GetName()); err != nil { + if err := SetSessionCookie(w, response.Username, response.Session.GetName()); err != nil { return nil, trace.Wrap(err) } return nil, httplib.SafeRedirect(w, r, response.Req.ClientRedirectURL) @@ -1163,6 +1170,12 @@ type CreateSessionReq struct { SecondFactorToken string `json:"second_factor_token"` } +// String returns text description of this response +func (r *CreateSessionResponse) String() string { + return fmt.Sprintf("WebSession(type=%v,token=%v,expires=%vs)", + r.Type, r.Token, r.ExpiresIn) +} + // CreateSessionResponse returns OAuth compabible data about // access token: https://tools.ietf.org/html/rfc6749 type CreateSessionResponse struct { @@ -1174,13 +1187,13 @@ type CreateSessionResponse struct { ExpiresIn int `json:"expires_in"` } -func NewSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) { +func newSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) { clt, err := ctx.GetClient() if err != nil { return nil, trace.Wrap(err) } - webSession := ctx.GetWebSession() - user, err := clt.GetUser(webSession.GetUser(), false) + token := ctx.getToken() + user, err := clt.GetUser(ctx.GetUser(), false) if err != nil { return nil, trace.Wrap(err) } @@ -1196,11 +1209,10 @@ func NewSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) { if err != nil { return nil, trace.Wrap(err) } - return &CreateSessionResponse{ Type: roundtrip.AuthBearer, - Token: webSession.GetBearerToken(), - ExpiresIn: int(webSession.GetBearerTokenExpiryTime().Sub(ctx.parent.clock.Now()) / time.Second), + Token: token.GetName(), + ExpiresIn: int(token.Expiry().Sub(ctx.parent.clock.Now()) / time.Second), }, nil } @@ -1243,17 +1255,28 @@ func (h *Handler) createWebSession(w http.ResponseWriter, r *http.Request, p htt return nil, trace.AccessDenied("bad auth credentials") } - if err := SetSession(w, req.User, webSession.GetName()); err != nil { + // Block and wait a few seconds for the session that was created to show up + // in the cache. If this request is not blocked here, it can get stuck in a + // racy session creation loop. + err = h.waitForWebSession(r.Context(), types.GetWebSessionRequest{ + User: req.User, + SessionID: webSession.GetName(), + }) + if err != nil { return nil, trace.Wrap(err) } - ctx, err := h.auth.ValidateSession(req.User, webSession.GetName()) + if err := SetSessionCookie(w, req.User, webSession.GetName()); err != nil { + return nil, trace.Wrap(err) + } + + ctx, err := h.auth.newSessionContext(req.User, webSession.GetName()) if err != nil { h.log.WithError(err).Warnf("Access attempt denied for user %q.", req.User) return nil, trace.AccessDenied("need auth") } - return NewSessionResponse(ctx) + return newSessionResponse(ctx) } // deleteSession is called to sign out user @@ -1283,29 +1306,23 @@ func (h *Handler) logout(w http.ResponseWriter, ctx *SessionContext) error { } // renewSession is called in two ways: -// - Without requestId: Creates new session that is about to expire. -// - With requestId: Creates new session that includes additional roles assigned with approving access request. -// -// It issues the new session and generates new session cookie. -// It's important to understand that the old session becomes effectively invalid. +// - Without requestId: Updates the existing session about to expire. +// - With requestId: Updates existing session with additional roles assigned with approving access request. func (h *Handler) renewSession(w http.ResponseWriter, r *http.Request, params httprouter.Params, ctx *SessionContext) (interface{}, error) { requestID := params.ByName("requestId") - newSess, err := ctx.ExtendWebSession(requestID) + newSession, err := ctx.extendWebSession(requestID) if err != nil { return nil, trace.Wrap(err) } - // transfer ownership over connections that were opened in the - // sessionContext - newContext, err := ctx.parent.ValidateSession(newSess.GetUser(), newSess.GetName()) + newContext, err := h.auth.newSessionContextFromSession(newSession) if err != nil { return nil, trace.Wrap(err) } - newContext.AddClosers(ctx.TransferClosers()...) - if err := SetSession(w, newSess.GetUser(), newSess.GetName()); err != nil { + if err := SetSessionCookie(w, newSession.GetUser(), newSession.GetName()); err != nil { return nil, trace.Wrap(err) } - return NewSessionResponse(newContext) + return newSessionResponse(newContext) } func (h *Handler) changePasswordWithToken(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { @@ -1318,27 +1335,27 @@ func (h *Handler) changePasswordWithToken(w http.ResponseWriter, r *http.Request if err != nil { return nil, trace.Wrap(err) } - ctx, err := h.auth.ValidateSession(sess.GetUser(), sess.GetName()) + ctx, err := h.auth.newSessionContext(sess.GetUser(), sess.GetName()) if err != nil { return nil, trace.Wrap(err) } - if err := SetSession(w, sess.GetUser(), sess.GetName()); err != nil { + if err := SetSessionCookie(w, sess.GetUser(), sess.GetName()); err != nil { return nil, trace.Wrap(err) } - return NewSessionResponse(ctx) + return newSessionResponse(ctx) } // createResetPasswordToken allows a UI user to reset a user's password. // This handler is also required for after creating new users. func (h *Handler) createResetPasswordToken(w http.ResponseWriter, r *http.Request, _ httprouter.Params, ctx *SessionContext) (interface{}, error) { - clt, err := ctx.GetClient() - if err != nil { + var req auth.CreateResetPasswordTokenRequest + if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) } - var req auth.CreateResetPasswordTokenRequest - if err := httplib.ReadJSON(r, &req); err != nil { + clt, err := ctx.GetClient() + if err != nil { return nil, trace.Wrap(err) } @@ -1347,7 +1364,6 @@ func (h *Handler) createResetPasswordToken(w http.ResponseWriter, r *http.Reques Name: req.Name, Type: req.Type, }) - if err != nil { return nil, trace.Wrap(err) } @@ -1460,14 +1476,14 @@ func (h *Handler) createSessionWithU2FSignResponse(w http.ResponseWriter, r *htt if err != nil { return nil, trace.AccessDenied("bad auth credentials") } - if err := SetSession(w, req.User, sess.GetName()); err != nil { + if err := SetSessionCookie(w, req.User, sess.GetName()); err != nil { return nil, trace.Wrap(err) } - ctx, err := h.auth.ValidateSession(req.User, sess.GetName()) + ctx, err := h.auth.newSessionContext(req.User, sess.GetName()) if err != nil { return nil, trace.AccessDenied("need auth") } - return NewSessionResponse(ctx) + return newSessionResponse(ctx) } // getClusters returns a list of cluster and its data. @@ -1541,7 +1557,7 @@ func (h *Handler) siteNodesGet(w http.ResponseWriter, r *http.Request, p httprou return nil, trace.BadParameter("invalid namespace %q", namespace) } - // Get a client to the Auth Server with the logged in users identity. The + // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of nodes. clt, err := ctx.GetUserClient(site) if err != nil { @@ -1561,7 +1577,7 @@ func (h *Handler) siteNodesGet(w http.ResponseWriter, r *http.Request, p httprou // GET /v1/webapi/sites/:site/namespaces/:namespace/connect?access_token=bearer_token¶ms= // // Due to the nature of websocket we can't POST parameters as is, so we have -// to add query parameters. The params query parameter is a url encodeed JSON strucrture: +// to add query parameters. The params query parameter is a URL-encoded JSON structure: // // {"server_id": "uuid", "login": "admin", "term": {"h": 120, "w": 100}, "sid": "123"} // @@ -1591,8 +1607,8 @@ func (h *Handler) siteNodeConnect( return nil, trace.Wrap(err) } - h.log.Debugf("New terminal request for ns=%s, server=%s, login=%s, sid=%s.", - req.Namespace, req.Server, req.Login, req.SessionID) + h.log.Debugf("New terminal request for ns=%s, server=%s, login=%s, sid=%s, websid=%s.", + req.Namespace, req.Server, req.Login, req.SessionID, ctx.GetSessionID()) authAccessPoint, err := site.CachingAccessPoint() if err != nil { @@ -1623,7 +1639,7 @@ func (h *Handler) siteNodeConnect( } // start the websocket session with a web-based terminal: - h.log.Infof("Getting terminal to '%#v'.", req) + h.log.Infof("Getting terminal to %#v.", req) term.Serve(w, r) return nil, nil @@ -2231,12 +2247,12 @@ func (h *Handler) AuthenticateRequest(w http.ResponseWriter, r *http.Request, ch } return nil, trace.AccessDenied(missingCookieMsg) } - d, err := DecodeCookie(cookie.Value) + decodedCookie, err := DecodeCookie(cookie.Value) if err != nil { logger.WithError(err).Warn("Failed to decode cookie.") return nil, trace.AccessDenied("failed to decode cookie") } - ctx, err := h.auth.ValidateSession(d.User, d.SID) + ctx, err := h.auth.validateSession(r.Context(), decodedCookie.User, decodedCookie.SID) if err != nil { logger.WithError(err).Warn("Invalid session.") ClearSession(w) @@ -2248,9 +2264,8 @@ func (h *Handler) AuthenticateRequest(w http.ResponseWriter, r *http.Request, ch logger.WithError(err).Warn("No auth headers.") return nil, trace.AccessDenied("need auth") } - - if subtle.ConstantTimeCompare([]byte(creds.Password), []byte(ctx.GetWebSession().GetBearerToken())) != 1 { - logger.Warn("Request failed: bad bearer token.") + if err := ctx.validateBearerToken(r.Context(), creds.Password); err != nil { + logger.WithError(err).Warn("Request failed: bad bearer token.") return nil, trace.AccessDenied("bad bearer token") } } diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 2fd59ccf72f..ec5d36470cd 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -44,6 +44,7 @@ import ( "golang.org/x/text/encoding/unicode" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/mocku2f" "github.com/gravitational/teleport/lib/auth/u2f" @@ -71,11 +72,13 @@ import ( "github.com/beevik/etree" "github.com/gogo/protobuf/proto" + "github.com/google/go-cmp/cmp" "github.com/jonboulle/clockwork" lemma_secret "github.com/mailgun/lemma/secret" "github.com/pborman/uuid" "github.com/pquerna/otp/totp" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" . "gopkg.in/check.v1" kyaml "k8s.io/apimachinery/pkg/util/yaml" ) @@ -123,20 +126,12 @@ func (s *WebSuite) SetUpSuite(c *C) { os.Unsetenv(teleport.DebugEnvVar) utils.InitLoggerForTests(testing.Verbose()) - // configure tests to use static assets from webassets/teleport: - debugAssetsPath = "../../webassets/teleport" - os.Setenv(teleport.DebugEnvVar, "true") - var err error s.mockU2F, err = mocku2f.Create() c.Assert(err, IsNil) c.Assert(s.mockU2F, NotNil) } -func (s *WebSuite) TearDownSuite(c *C) { - os.Unsetenv(teleport.DebugEnvVar) -} - func (s *WebSuite) SetUpTest(c *C) { u, err := user.Current() c.Assert(err, IsNil) @@ -246,16 +241,22 @@ func (s *WebSuite) SetUpTest(c *C) { ) c.Assert(err, IsNil) + // Expired sessions are purged immediately + var sessionLingeringThreshold time.Duration = 0 + fs, err := NewDebugFileSystem("../../webassets/teleport") + c.Assert(err, IsNil) handler, err := NewHandler(Config{ - Proxy: revTunServer, - AuthServers: utils.FromAddr(s.server.Addr()), - DomainName: s.server.ClusterName(), - ProxyClient: s.proxyClient, - CipherSuites: utils.DefaultCipherSuites(), - AccessPoint: s.proxyClient, - Context: context.Background(), - HostUUID: proxyID, - Emitter: s.proxyClient, + Proxy: revTunServer, + AuthServers: utils.FromAddr(s.server.Addr()), + DomainName: s.server.ClusterName(), + ProxyClient: s.proxyClient, + CipherSuites: utils.DefaultCipherSuites(), + AccessPoint: s.proxyClient, + Context: context.Background(), + HostUUID: proxyID, + Emitter: s.proxyClient, + StaticFS: fs, + cachedSessionLingeringThreshold: &sessionLingeringThreshold, }, SetSessionStreamPollPeriod(200*time.Millisecond), SetClock(s.clock)) c.Assert(err, IsNil) @@ -294,6 +295,17 @@ func (s *WebSuite) TearDownTest(c *C) { s.proxyTunnel.Close() } +func (r *authPack) renewSession(ctx context.Context, t *testing.T) *roundtrip.Response { + resp, err := r.clt.PostJSON(ctx, r.clt.Endpoint("webapi", "sessions", "renew"), nil) + require.NoError(t, err) + return resp +} + +func (r *authPack) validateAPI(ctx context.Context, t *testing.T) { + _, err := r.clt.Get(ctx, r.clt.Endpoint("webapi", "sites"), url.Values{}) + require.NoError(t, err) +} + type authPack struct { otpSecret string user string @@ -303,28 +315,6 @@ type authPack struct { cookies []*http.Cookie } -func (s *WebSuite) authPackFromResponse(c *C, re *roundtrip.Response) *authPack { - var sess *CreateSessionResponse - c.Assert(json.Unmarshal(re.Bytes(), &sess), IsNil) - - jar, err := cookiejar.New(nil) - c.Assert(err, IsNil) - - clt := s.client(roundtrip.BearerAuth(sess.Token), roundtrip.CookieJar(jar)) - jar.SetCookies(s.url(), re.Cookies()) - - session, err := sess.response() - c.Assert(err, IsNil) - if session.ExpiresIn < 0 { - c.Errorf("expected expiry time to be in the future but got %v", session.ExpiresIn) - } - return &authPack{ - session: session, - clt: clt, - cookies: re.Cookies(), - } -} - // authPack returns new authenticated package consisting of created valid // user, otp token, created web session and authenticated client. func (s *WebSuite) authPack(c *C, user string) *authPack { @@ -608,43 +598,6 @@ func (s *WebSuite) TestPasswordChange(c *C) { c.Assert(err, IsNil) } -func (s *WebSuite) TestWebSessionsRenew(c *C) { - pack := s.authPack(c, "foo") - - // make sure we can use client to make authenticated requests - // before we issue this request, we will recover session id and bearer token - // - prevSessionCookie := *pack.cookies[0] - prevBearerToken := pack.session.Token - re, err := pack.clt.PostJSON(context.Background(), pack.clt.Endpoint("webapi", "sessions", "renew"), nil) - c.Assert(err, IsNil) - - newPack := s.authPackFromResponse(c, re) - - // new session is functioning - _, err = newPack.clt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, IsNil) - - // old session is stil valid too (until it expires) - jar, err := cookiejar.New(nil) - c.Assert(err, IsNil) - oldClt := s.client(roundtrip.BearerAuth(prevBearerToken), roundtrip.CookieJar(jar)) - jar.SetCookies(s.url(), []*http.Cookie{&prevSessionCookie}) - _, err = oldClt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, IsNil) - - // now delete session - _, err = newPack.clt.Delete( - context.Background(), - pack.clt.Endpoint("webapi", "sessions")) - c.Assert(err, IsNil) - - // subsequent requests trying to use this session will fail - _, err = newPack.clt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) - c.Assert(err, NotNil) - c.Assert(trace.IsAccessDenied(err), Equals, true) -} - func (s *WebSuite) TestWebSessionsBadInput(c *C) { user := "bob" pass := "abc123" @@ -981,13 +934,12 @@ func (s *WebSuite) TestTerminal(c *C) { defer ws.Close() termHandler := newTerminalHandler() - stream, err := termHandler.asTerminalStream(ws) - c.Assert(err, IsNil) + stream := termHandler.asTerminalStream(ws) _, err = io.WriteString(stream, "echo vinsong\r\n") c.Assert(err, IsNil) - err = s.waitForOutput(stream, "vinsong") + err = waitForOutput(stream, "vinsong") c.Assert(err, IsNil) } @@ -1039,13 +991,12 @@ func (s *WebSuite) TestWebAgentForward(c *C) { defer ws.Close() termHandler := newTerminalHandler() - stream, err := termHandler.asTerminalStream(ws) - c.Assert(err, IsNil) + stream := termHandler.asTerminalStream(ws) _, err = io.WriteString(stream, "echo $SSH_AUTH_SOCK\r\n") c.Assert(err, IsNil) - err = s.waitForOutput(stream, "/") + err = waitForOutput(stream, "/") c.Assert(err, IsNil) } @@ -1058,15 +1009,14 @@ func (s *WebSuite) TestActiveSessions(c *C) { defer ws.Close() termHandler := newTerminalHandler() - stream, err := termHandler.asTerminalStream(ws) - c.Assert(err, IsNil) + stream := termHandler.asTerminalStream(ws) // To make sure we have a session. _, err = io.WriteString(stream, "echo vinsong\r\n") c.Assert(err, IsNil) // Make sure server has replied. - err = s.waitForOutput(stream, "vinsong") + err = waitForOutput(stream, "vinsong") c.Assert(err, IsNil) // Make sure this session appears in the list of active sessions. @@ -1167,8 +1117,7 @@ func (s *WebSuite) TestCloseConnectionsOnLogout(c *C) { defer ws.Close() termHandler := newTerminalHandler() - stream, err := termHandler.asTerminalStream(ws) - c.Assert(err, IsNil) + stream := termHandler.asTerminalStream(ws) // to make sure we have a session _, err = io.WriteString(stream, "expr 137 + 39\r\n") @@ -1908,6 +1857,114 @@ func (s *WebSuite) TestCreateAppSession(c *C) { } } +// TestWebSessionsRenewDoesNotBreakExistingTerminalSession validates that the +// session renewed via one proxy does not force the terminals created by another +// proxy to disconnect +// +// See https://github.com/gravitational/teleport/issues/5265 +func TestWebSessionsRenewDoesNotBreakExistingTerminalSession(t *testing.T) { + env := newWebPack(t, 2) + defer env.close(t) + + proxy1, proxy2 := env.proxies[0], env.proxies[1] + // Connect to both proxies + pack1 := proxy1.authPack(t, "foo") + pack2 := proxy2.authPackFromPack(t, pack1) + + ws := proxy2.makeTerminal(t, pack2, session.NewID()) + defer ws.Close() + + // Advance the time before renewing the session. + // This will allow the new session to have a more plausible + // expiration + const delta = 30 * time.Second + env.clock.Advance(auth.BearerTokenTTL - delta) + + // Renew the session using the 1st proxy + resp := pack1.renewSession(context.TODO(), t) + + // Expire the old session and make sure it has been removed. + // The bearer token is also removed after this point, so we have to + // use the new session data for future connects + env.clock.Advance(delta + 1*time.Second) + pack2 = proxy2.authPackFromResponse(t, resp) + + // Verify that access via the 2nd proxy also works for the same session + pack2.validateAPI(context.TODO(), t) + + // Check whether the terminal session is still active + validateTerminalStream(t, ws) +} + +// TestWebSessionsRenewAllowsOldBearerTokenToLinger validates that the +// bearer token bound to the previous session is still active after the +// session renewal, if the renewal happens with a time margin. +// +// See https://github.com/gravitational/teleport/issues/5265 +func TestWebSessionsRenewAllowsOldBearerTokenToLinger(t *testing.T) { + // Login to implicitly create a new web session + env := newWebPack(t, 1) + defer env.close(t) + + proxy := env.proxies[0] + pack := proxy.authPack(t, "foo") + + delta := 30 * time.Second + // Advance the time before renewing the session. + // This will allow the new session to have a more plausible + // expiration + env.clock.Advance(auth.BearerTokenTTL - delta) + + // make sure we can use client to make authenticated requests + // before we issue this request, we will recover session id and bearer token + // + prevSessionCookie := *pack.cookies[0] + prevBearerToken := pack.session.Token + resp := pack.renewSession(context.TODO(), t) + + newPack := proxy.authPackFromResponse(t, resp) + + // new session is functioning + newPack.validateAPI(context.TODO(), t) + + sessionCookie := *newPack.cookies[0] + bearerToken := newPack.session.Token + require.NotEmpty(t, bearerToken) + require.NotEmpty(t, cmp.Diff(bearerToken, prevBearerToken)) + + prevSessionID := decodeSessionCookie(t, prevSessionCookie.Value) + activeSessionID := decodeSessionCookie(t, sessionCookie.Value) + require.NotEmpty(t, cmp.Diff(prevSessionID, activeSessionID)) + + // old session is still valid + jar, err := cookiejar.New(nil) + require.NoError(t, err) + + oldClt := proxy.newClient(t, roundtrip.BearerAuth(prevBearerToken), roundtrip.CookieJar(jar)) + jar.SetCookies(&proxy.webURL, []*http.Cookie{&prevSessionCookie}) + _, err = oldClt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) + require.NoError(t, err) + + // now expire the old session and make sure it has been removed + env.clock.Advance(delta) + + _, err = proxy.client.GetWebSession(context.TODO(), types.GetWebSessionRequest{ + User: "foo", + SessionID: prevSessionID, + }) + require.Regexp(t, "^key.*not found$", err.Error()) + + // now delete session + _, err = newPack.clt.Delete( + context.Background(), + pack.clt.Endpoint("webapi", "sessions")) + require.NoError(t, err) + + // subsequent requests to use this session will fail + _, err = newPack.clt.Get(context.Background(), pack.clt.Endpoint("webapi", "sites"), url.Values{}) + require.True(t, trace.IsAccessDenied(err)) +} + type authProviderMock struct { server services.ServerV2 } @@ -1971,7 +2028,7 @@ func (s *WebSuite) makeTerminal(pack *authPack, opts ...session.ID) (*websocket. return ws, nil } -func (s *WebSuite) waitForOutput(stream *terminalStream, substr string) error { +func waitForOutput(stream *terminalStream, substr string) error { tickerCh := time.Tick(250 * time.Millisecond) timeoutCh := time.After(10 * time.Second) @@ -2151,6 +2208,423 @@ func newTerminalHandler() TerminalHandler { } } +func decodeSessionCookie(t *testing.T, value string) (sessionID string) { + sessionBytes, err := hex.DecodeString(value) + require.NoError(t, err) + var cookie struct { + User string `json:"user"` + SessionID string `json:"sid"` + } + require.NoError(t, json.Unmarshal(sessionBytes, &cookie)) + return cookie.SessionID +} + func (r CreateSessionResponse) response() (*CreateSessionResponse, error) { return &CreateSessionResponse{Type: r.Type, Token: r.Token, ExpiresIn: r.ExpiresIn}, nil } + +func newWebPack(t *testing.T, numProxies int) *webPack { + clock := clockwork.NewFakeClock() + + authServer, err := auth.NewTestAuthServer(auth.TestAuthServerConfig{ + ClusterName: "localhost", + Dir: t.TempDir(), + Clock: clock, + }) + require.NoError(t, err) + + server, err := authServer.NewTestTLSServer() + require.NoError(t, err) + + // start auth server + certs, err := server.Auth().GenerateServerKeys(auth.GenerateServerKeysRequest{ + HostID: hostID, + NodeName: server.ClusterName(), + Roles: teleport.Roles{teleport.RoleNode}, + }) + require.NoError(t, err) + + signer, err := sshutils.NewSigner(certs.Key, certs.Cert) + require.NoError(t, err) + + const nodeID = "node" + nodeClient, err := server.NewClient(auth.TestIdentity{ + I: auth.BuiltinRole{ + Role: teleport.RoleNode, + Username: nodeID, + }, + }) + require.NoError(t, err) + + hostSigners := []ssh.Signer{signer} + // create SSH service: + nodeDataDir := t.TempDir() + node, err := regular.New( + utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"}, + server.ClusterName(), + hostSigners, + nodeClient, + nodeDataDir, + "", + utils.NetAddr{}, + regular.SetUUID(nodeID), + regular.SetNamespace(defaults.Namespace), + regular.SetShell("/bin/sh"), + regular.SetSessionServer(nodeClient), + regular.SetEmitter(nodeClient), + regular.SetPAMConfig(&pam.Config{Enabled: false}), + regular.SetBPF(&bpf.NOP{}), + regular.SetClock(clock), + ) + require.NoError(t, err) + + require.NoError(t, node.Start()) + require.NoError(t, auth.CreateUploaderDir(nodeDataDir)) + + var proxies []*proxy + for p := 0; p < numProxies; p++ { + proxyID := fmt.Sprintf("proxy%v", p) + proxies = append(proxies, createProxy(t, proxyID, node, server, hostSigners, clock)) + } + + // Wait for proxies to fully register before starting the test. + for start := time.Now(); ; { + proxies, err := proxies[0].client.GetProxies() + require.NoError(t, err) + if len(proxies) != numProxies { + break + } + if time.Since(start) > 5*time.Second { + t.Fatal("Proxy didn't register within 5s after startup.") + } + } + + return &webPack{ + proxies: proxies, + server: server, + node: node, + clock: clock, + } +} + +func createProxy(t *testing.T, proxyID string, node *regular.Server, authServer *auth.TestTLSServer, + hostSigners []ssh.Signer, clock clockwork.FakeClock) *proxy { + + // create reverse tunnel service: + client, err := authServer.NewClient(auth.TestIdentity{ + I: auth.BuiltinRole{ + Role: teleport.RoleProxy, + Username: proxyID, + }, + }) + require.NoError(t, err) + + revTunListener, err := net.Listen("tcp", fmt.Sprintf("%v:0", authServer.ClusterName())) + require.NoError(t, err) + + revTunServer, err := reversetunnel.NewServer(reversetunnel.Config{ + ID: node.ID(), + Listener: revTunListener, + ClientTLS: client.TLSConfig(), + ClusterName: authServer.ClusterName(), + HostSigners: hostSigners, + LocalAuthClient: client, + LocalAccessPoint: client, + Emitter: client, + NewCachingAccessPoint: auth.NoCache, + DirectClusters: []reversetunnel.DirectCluster{{Name: authServer.ClusterName(), Client: client}}, + DataDir: t.TempDir(), + }) + require.NoError(t, err) + + proxyServer, err := regular.New( + utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"}, + authServer.ClusterName(), + hostSigners, + client, + t.TempDir(), + "", + utils.NetAddr{}, + regular.SetUUID(proxyID), + regular.SetProxyMode(revTunServer), + regular.SetSessionServer(client), + regular.SetEmitter(client), + regular.SetNamespace(defaults.Namespace), + regular.SetBPF(&bpf.NOP{}), + regular.SetClock(clock), + ) + require.NoError(t, err) + + fs, err := NewDebugFileSystem("../../webassets/teleport") + require.NoError(t, err) + handler, err := NewHandler(Config{ + Proxy: revTunServer, + AuthServers: utils.FromAddr(authServer.Addr()), + DomainName: authServer.ClusterName(), + ProxyClient: client, + CipherSuites: utils.DefaultCipherSuites(), + AccessPoint: client, + Context: context.Background(), + HostUUID: proxyID, + Emitter: client, + StaticFS: fs, + }, SetSessionStreamPollPeriod(200*time.Millisecond), SetClock(clock)) + require.NoError(t, err) + + webServer := httptest.NewUnstartedServer(handler) + webServer.StartTLS() + require.NoError(t, proxyServer.Start()) + + proxyAddr := utils.MustParseAddr(proxyServer.Addr()) + addr := utils.MustParseAddr(webServer.Listener.Addr().String()) + handler.handler.cfg.ProxyWebAddr = *addr + handler.handler.cfg.ProxySSHAddr = *proxyAddr + _, sshPort, err := net.SplitHostPort(proxyAddr.String()) + require.NoError(t, err) + handler.handler.sshPort = sshPort + + url, err := url.Parse("https://" + webServer.Listener.Addr().String()) + require.NoError(t, err) + + return &proxy{ + clock: clock, + auth: authServer, + client: client, + revTun: revTunServer, + node: node, + proxy: proxyServer, + web: webServer, + handler: handler, + webURL: *url, + } +} + +// webPack represents the state of a single web test. +// It replicates most of the WebSuite and serves to gradually +// transition the test suite to use the testing package +// directly. +type webPack struct { + proxies []*proxy + server *auth.TestTLSServer + node *regular.Server + clock clockwork.FakeClock +} + +func (r *webPack) close(t *testing.T) { + for _, p := range r.proxies { + p.web.Close() + p.proxy.Close() + p.revTun.Close() + } + require.NoError(t, r.node.Close()) + require.NoError(t, r.server.Close()) + +} + +type proxy struct { + clock clockwork.FakeClock + client *auth.Client + auth *auth.TestTLSServer + revTun reversetunnel.Server + node *regular.Server + proxy *regular.Server + handler *RewritingHandler + web *httptest.Server + webURL url.URL +} + +// authPack returns new authenticated package consisting of created valid +// user, otp token, created web session and authenticated client. +func (r *proxy) authPack(t *testing.T, user string) *authPack { + const ( + loginUser = "user" + pass = "abc123" + rawSecret = "def456" + ) + otpSecret := base32.StdEncoding.EncodeToString([]byte(rawSecret)) + + ap, err := services.NewAuthPreference(services.AuthPreferenceSpecV2{ + Type: teleport.Local, + SecondFactor: teleport.OTP, + }) + require.NoError(t, err) + + err = r.auth.Auth().SetAuthPreference(ap) + require.NoError(t, err) + + r.createUser(context.TODO(), t, user, loginUser, pass, otpSecret) + + // create a valid otp token + validToken, err := totp.GenerateCode(otpSecret, r.clock.Now()) + require.NoError(t, err) + + clt := r.newClient(t) + req := CreateSessionReq{ + User: user, + Pass: pass, + SecondFactorToken: validToken, + } + + csrfToken := "2ebcb768d0090ea4368e42880c970b61865c326172a4a2343b645cf5d7f20992" + resp := login(t, clt, csrfToken, csrfToken, req) + + var rawSession *CreateSessionResponse + require.NoError(t, json.Unmarshal(resp.Bytes(), &rawSession)) + + session, err := rawSession.response() + require.NoError(t, err) + + jar, err := cookiejar.New(nil) + require.NoError(t, err) + + clt = r.newClient(t, roundtrip.BearerAuth(session.Token), roundtrip.CookieJar(jar)) + jar.SetCookies(&r.webURL, resp.Cookies()) + + return &authPack{ + otpSecret: otpSecret, + user: user, + login: loginUser, + session: session, + clt: clt, + cookies: resp.Cookies(), + } +} + +func (r *proxy) authPackFromPack(t *testing.T, pack *authPack) *authPack { + jar, err := cookiejar.New(nil) + require.NoError(t, err) + + clt := r.newClient(t, roundtrip.BearerAuth(pack.session.Token), roundtrip.CookieJar(jar)) + jar.SetCookies(&r.webURL, pack.cookies) + + result := *pack + result.clt = clt + return &result +} + +func (r *proxy) authPackFromResponse(t *testing.T, httpResp *roundtrip.Response) *authPack { + var resp *CreateSessionResponse + require.NoError(t, json.Unmarshal(httpResp.Bytes(), &resp)) + + jar, err := cookiejar.New(nil) + require.NoError(t, err) + + clt := r.newClient(t, roundtrip.BearerAuth(resp.Token), roundtrip.CookieJar(jar)) + jar.SetCookies(&r.webURL, httpResp.Cookies()) + + session, err := resp.response() + require.NoError(t, err) + if session.ExpiresIn < 0 { + t.Errorf("Expected expiry time to be in the future but got %v", session.ExpiresIn) + } + return &authPack{ + session: session, + clt: clt, + cookies: httpResp.Cookies(), + } +} + +func (r *proxy) createUser(ctx context.Context, t *testing.T, user, login, pass, otpSecret string) { + teleUser, err := services.NewUser(user) + require.NoError(t, err) + + role := services.RoleForUser(teleUser) + role.SetLogins(services.Allow, []string{login}) + options := role.GetOptions() + options.ForwardAgent = services.NewBool(true) + role.SetOptions(options) + err = r.auth.Auth().UpsertRole(ctx, role) + require.NoError(t, err) + + teleUser.AddRole(role.GetName()) + teleUser.SetCreatedBy(services.CreatedBy{ + User: services.UserRef{Name: "some-auth-user"}, + }) + + err = r.auth.Auth().CreateUser(ctx, teleUser) + require.NoError(t, err) + + err = r.auth.Auth().UpsertPassword(user, []byte(pass)) + require.NoError(t, err) + + if otpSecret != "" { + dev, err := services.NewTOTPDevice("otp", otpSecret, r.clock.Now()) + require.NoError(t, err) + err = r.auth.Auth().UpsertMFADevice(ctx, user, dev) + require.NoError(t, err) + } +} + +func (r *proxy) newClient(t *testing.T, opts ...roundtrip.ClientParam) *client.WebClient { + opts = append(opts, roundtrip.HTTPClient(client.NewInsecureWebClient())) + clt, err := client.NewWebClient(r.webURL.String(), opts...) + require.NoError(t, err) + return clt +} + +func (r *proxy) makeTerminal(t *testing.T, pack *authPack, sessionID session.ID) *websocket.Conn { + u := url.URL{ + Host: r.webURL.Host, + Scheme: client.WSS, + Path: fmt.Sprintf("/v1/webapi/sites/%v/connect", currentSiteShortcut), + } + data, err := json.Marshal(TerminalRequest{ + Server: r.node.ID(), + Login: pack.login, + Term: session.TerminalParams{ + W: 100, + H: 100, + }, + SessionID: sessionID, + }) + require.NoError(t, err) + + q := u.Query() + q.Set("params", string(data)) + q.Set(roundtrip.AccessTokenQueryParam, pack.session.Token) + u.RawQuery = q.Encode() + + wscfg, err := websocket.NewConfig(u.String(), "http://localhost") + wscfg.TlsConfig = &tls.Config{ + InsecureSkipVerify: true, + } + require.NoError(t, err) + + for _, cookie := range pack.cookies { + wscfg.Header.Add("Cookie", cookie.String()) + } + + ws, err := websocket.DialConfig(wscfg) + require.NoError(t, err) + + return ws +} + +func login(t *testing.T, clt *client.WebClient, cookieToken, reqToken string, reqData interface{}) *roundtrip.Response { + resp, err := httplib.ConvertResponse(clt.RoundTrip(func() (*http.Response, error) { + data, err := json.Marshal(reqData) + if err != nil { + return nil, err + } + req, err := http.NewRequest("POST", clt.Endpoint("webapi", "sessions"), bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + addCSRFCookieToReq(req, cookieToken) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(csrf.HeaderName, reqToken) + return clt.HTTPClient().Do(req) + })) + require.NoError(t, err) + return resp +} + +func validateTerminalStream(t *testing.T, conn *websocket.Conn) { + termHandler := newTerminalHandler() + stream := termHandler.asTerminalStream(conn) + _, err := io.WriteString(stream, "echo foo\r\n") + require.NoError(t, err) + + err = waitForOutput(stream, "foo") + require.NoError(t, err) +} diff --git a/lib/web/apps.go b/lib/web/apps.go index b5d65860c69..0f630a13404 100644 --- a/lib/web/apps.go +++ b/lib/web/apps.go @@ -21,7 +21,6 @@ package web import ( "context" "net/http" - "time" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/backend" @@ -30,6 +29,7 @@ import ( "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/web/app" @@ -115,7 +115,7 @@ func (h *Handler) createAppSession(w http.ResponseWriter, r *http.Request, p htt // used for request routing. ws, err := authClient.CreateAppSession(r.Context(), services.CreateAppSessionRequest{ Username: ctx.GetUser(), - ParentSession: ctx.sess.GetName(), + ParentSession: ctx.GetSessionID(), PublicAddr: result.PublicAddr, ClusterName: result.ClusterName, }) @@ -124,9 +124,9 @@ func (h *Handler) createAppSession(w http.ResponseWriter, r *http.Request, p htt } // Block and wait a few seconds for the session that was created to show up - // in the cache. If this request is not blocked here, it can get struck in a + // in the cache. If this request is not blocked here, it can get stuck in a // racy session creation loop. - err = h.waitForSession(r.Context(), ws.GetName()) + err = h.waitForAppSession(r.Context(), ws.GetName()) if err != nil { return nil, trace.Wrap(err) } @@ -174,18 +174,24 @@ func (h *Handler) createAppSession(w http.ResponseWriter, r *http.Request, p htt }, nil } -// waitForSession will block until the requested session shows up in the +// waitForAppSession will block until the requested application session shows up in the // cache or a timeout occurs. -func (h *Handler) waitForSession(ctx context.Context, sessionID string) error { - timeout := time.NewTimer(defaults.WebHeadersTimeout) - defer timeout.Stop() - +func (h *Handler) waitForAppSession(ctx context.Context, sessionID string) error { + _, err := h.cfg.AccessPoint.GetAppSession(ctx, services.GetAppSessionRequest{SessionID: sessionID}) + if err == nil { + return nil + } + logger := h.log.WithField("session", sessionID) + if !trace.IsNotFound(err) { + logger.WithError(err).Debug("Failed to query application session.") + } // Establish a watch on application session. watcher, err := h.cfg.AccessPoint.NewWatcher(ctx, services.Watch{ Name: teleport.ComponentAppProxy, Kinds: []services.WatchKind{ - services.WatchKind{ - Kind: services.KindWebSession, + { + Kind: services.KindWebSession, + SubKind: services.KindAppSession, }, }, MetricComponent: teleport.ComponentAppProxy, @@ -194,48 +200,20 @@ func (h *Handler) waitForSession(ctx context.Context, sessionID string) error { return trace.Wrap(err) } defer watcher.Close() - - select { - // Received an event, first event should always be an initialize event. - case event := <-watcher.Events(): - if event.Type != backend.OpInit { - return trace.BadParameter("expected init event, got %v instead", event.Type) + matchEvent := func(event services.Event) (services.Resource, error) { + if event.Type == backend.OpPut && + event.Resource.GetKind() == services.KindWebSession && + event.Resource.GetSubKind() == services.KindAppSession && + event.Resource.GetName() == sessionID { + return event.Resource, nil } - // Watcher closed, probably due to a network error. - case <-watcher.Done(): - return trace.ConnectionProblem(watcher.Error(), "watcher is closed") - // Timed out waiting for initialize event. - case <-timeout.C: - return trace.BadParameter("timed out waiting for initialize event") + return nil, trace.CompareFailed("no match") } - - // Check if the session exists in the backend. - _, err = h.cfg.AccessPoint.GetAppSession(ctx, services.GetAppSessionRequest{ - SessionID: sessionID, - }) - if err == nil { - return nil - } - - for { - select { - // If the event is the expected one, return right away. - case event := <-watcher.Events(): - if event.Resource.GetKind() != services.KindWebSession { - return trace.BadParameter("unexpected event: %v.", event.Resource.GetKind()) - } - if event.Type == backend.OpPut && event.Resource.GetName() == sessionID { - return nil - } - // Watcher closed, probably due to a network error. - case <-watcher.Done(): - return trace.ConnectionProblem(watcher.Error(), "watcher is closed") - // Timed out waiting for initialize event. - case <-timeout.C: - return trace.BadParameter("timed out waiting for session") - - } + _, err = local.WaitForEvent(ctx, watcher, local.EventMatcherFunc(matchEvent), h.clock) + if err != nil { + logger.WithError(err).Warn("Failed to wait for application session.") } + return trace.Wrap(err) } func (h *Handler) validateAppSessionRequest(ctx context.Context, req *CreateAppSessionRequest) (*validateAppSessionResult, error) { diff --git a/lib/web/cookie.go b/lib/web/cookie.go index 2f0ae4df64b..f243fff8556 100644 --- a/lib/web/cookie.go +++ b/lib/web/cookie.go @@ -49,7 +49,7 @@ func DecodeCookie(b string) (*SessionCookie, error) { return c, nil } -func SetSession(w http.ResponseWriter, user, sid string) error { +func SetSessionCookie(w http.ResponseWriter, user, sid string) error { d, err := EncodeCookie(user, sid) if err != nil { return err diff --git a/lib/web/saml.go b/lib/web/saml.go index da0d9aa35d5..d34f27ff515 100644 --- a/lib/web/saml.go +++ b/lib/web/saml.go @@ -128,7 +128,7 @@ func (h *Handler) samlACS(w http.ResponseWriter, r *http.Request, p httprouter.P logger.WithError(err).Warn("Unable to verify CSRF token.") return nil, trace.AccessDenied("access denied") } - if err := SetSession(w, response.Username, response.Session.GetName()); err != nil { + if err := SetSessionCookie(w, response.Username, response.Session.GetName()); err != nil { return nil, trace.Wrap(err) } return nil, httplib.SafeRedirect(w, r, response.Req.ClientRedirectURL) diff --git a/lib/web/sessions.go b/lib/web/sessions.go index ae2b9b7c684..cf5cdbafefe 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -20,87 +20,98 @@ import ( "context" "crypto/tls" "crypto/x509" + "fmt" "io" "net" - "net/http" "sync" "time" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" + "github.com/gravitational/teleport" apiclient "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/proto" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/u2f" + "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/trace" - "github.com/gravitational/ttlmap" "github.com/jonboulle/clockwork" "github.com/sirupsen/logrus" ) -// SessionContext is a context associated with users' -// web session, it stores connected client that persists -// between requests for example to avoid connecting -// to the auth server on every page hit +// SessionContext is a context associated with a user's +// web session. An instance of the context is created for +// each web session generated for the user and provides +// a basic client cache for remote auth server connections. type SessionContext struct { - sync.Mutex - logrus.FieldLogger - sess services.WebSession - user string - clt auth.ClientI + log logrus.FieldLogger + user string + clt auth.ClientI + parent *sessionCache + // resources is persistent resource store this context is bound to. + // The store maintains a list of resources between session renewals + resources *sessionResources + // session refers the web session created for the user. + session services.WebSession + + mu sync.Mutex remoteClt map[string]auth.ClientI - parent *sessionCache - closers []io.Closer } +// String returns the text representation of this context +func (c *SessionContext) String() string { + return fmt.Sprintf("WebSession(user=%v,id=%v,expires=%v,bearer=%v,bearer_expires=%v)", + c.user, + c.session.GetName(), + c.session.GetExpiryTime(), + c.session.GetBearerToken(), + c.session.GetBearerTokenExpiryTime(), + ) +} + +// AddClosers adds the specified closers to this context func (c *SessionContext) AddClosers(closers ...io.Closer) { - c.Lock() - defer c.Unlock() - c.closers = append(c.closers, closers...) + c.resources.addClosers(closers...) } +// RemoveCloser removes the specified closer from this context func (c *SessionContext) RemoveCloser(closer io.Closer) { - c.Lock() - defer c.Unlock() - for i := range c.closers { - if c.closers[i] == closer { - c.closers = append(c.closers[:i], c.closers[i+1:]...) - return - } - } -} - -func (c *SessionContext) TransferClosers() []io.Closer { - c.Lock() - defer c.Unlock() - closers := c.closers - c.closers = nil - return closers + c.resources.removeCloser(closer) } +// Invalidate invalidates this context by removing the underlying session +// and closing all underlying closers func (c *SessionContext) Invalidate() error { - return c.parent.InvalidateSession(c) + return c.parent.invalidateSession(c) +} + +func (c *SessionContext) validateBearerToken(ctx context.Context, token string) error { + _, err := c.parent.readBearerToken(ctx, types.GetWebTokenRequest{ + User: c.user, + Token: token, + }) + return trace.Wrap(err) } func (c *SessionContext) addRemoteClient(siteName string, remoteClient auth.ClientI) { - c.Lock() - defer c.Unlock() - + c.mu.Lock() + defer c.mu.Unlock() c.remoteClt[siteName] = remoteClient } func (c *SessionContext) getRemoteClient(siteName string) (auth.ClientI, bool) { - c.Lock() - defer c.Unlock() - + c.mu.Lock() + defer c.mu.Unlock() remoteClt, ok := c.remoteClt[siteName] return remoteClt, ok } @@ -116,33 +127,24 @@ func (c *SessionContext) GetClient() (auth.ClientI, error) { // returned. func (c *SessionContext) GetUserClient(site reversetunnel.RemoteSite) (auth.ClientI, error) { // get the name of the current cluster - clt, err := c.GetClient() - if err != nil { - return nil, trace.Wrap(err) - } - cn, err := clt.GetClusterName() + clusterName, err := c.clt.GetClusterName() if err != nil { return nil, trace.Wrap(err) } // if we're trying to access the local cluster, pass back the local client. - if cn.GetClusterName() == site.GetName() { - return clt, nil + if clusterName.GetClusterName() == site.GetName() { + return c.clt, nil } - // look to see if we already have a connection to this cluster + // check if we already have a connection to this cluster remoteClt, ok := c.getRemoteClient(site.GetName()) if !ok { - rClt, rConn, err := c.newRemoteClient(site) + rClt, err := c.newRemoteClient(site) if err != nil { return nil, trace.Wrap(err) } - // add a closer for the underlying connection - if rConn != nil { - c.AddClosers(rConn) - } - // we'll save the remote client in our session context so we don't have to // build a new connection next time. all remote clients will be closed when // the session context is closed. @@ -156,12 +158,12 @@ func (c *SessionContext) GetUserClient(site reversetunnel.RemoteSite) (auth.Clie // newRemoteClient returns a client to a remote cluster with the role of // the logged in user. -func (c *SessionContext) newRemoteClient(cluster reversetunnel.RemoteSite) (auth.ClientI, net.Conn, error) { +func (c *SessionContext) newRemoteClient(cluster reversetunnel.RemoteSite) (auth.ClientI, error) { clt, err := c.tryRemoteTLSClient(cluster) if err != nil { - return nil, nil, trace.Wrap(err) + return nil, trace.Wrap(err) } - return clt, nil, nil + return clt, nil } // clusterDialer returns DialContext function using cluster's dial function @@ -213,13 +215,14 @@ func (c *SessionContext) ClientTLSConfig(clusterName ...string) (*tls.Config, er } tlsConfig := utils.TLSConfig(c.parent.cipherSuites) - tlsCert, err := tls.X509KeyPair(c.sess.GetTLSCert(), c.sess.GetPriv()) + tlsCert, err := tls.X509KeyPair(c.session.GetTLSCert(), c.session.GetPriv()) if err != nil { return nil, trace.Wrap(err, "failed to parse TLS cert and key") } tlsConfig.Certificates = []tls.Certificate{tlsCert} tlsConfig.RootCAs = certPool tlsConfig.ServerName = auth.EncodeClusterName(c.parent.clusterName) + tlsConfig.Time = c.parent.clock.Now return tlsConfig, nil } @@ -236,25 +239,20 @@ func (c *SessionContext) GetUser() string { return c.user } -// GetWebSession returns a web session -func (c *SessionContext) GetWebSession() services.WebSession { - return c.sess -} - -// ExtendWebSession creates a new web session for this user +// extendWebSession creates a new web session for this user // based on the previous session -func (c *SessionContext) ExtendWebSession(accessRequestID string) (services.WebSession, error) { - sess, err := c.clt.ExtendWebSession(c.user, c.sess.GetName(), accessRequestID) +func (c *SessionContext) extendWebSession(accessRequestID string) (services.WebSession, error) { + session, err := c.clt.ExtendWebSession(c.user, c.session.GetName(), accessRequestID) if err != nil { return nil, trace.Wrap(err) } - return sess, nil + return session, nil } // GetAgent returns agent that can be used to answer challenges // for the web to ssh connection as well as certificate func (c *SessionContext) GetAgent() (agent.Agent, *ssh.Certificate, error) { - pub, _, _, _, err := ssh.ParseAuthorizedKey(c.sess.GetPub()) + pub, _, _, _, err := ssh.ParseAuthorizedKey(c.session.GetPub()) if err != nil { return nil, nil, trace.Wrap(err) } @@ -265,7 +263,7 @@ func (c *SessionContext) GetAgent() (agent.Agent, *ssh.Certificate, error) { if len(cert.ValidPrincipals) == 0 { return nil, nil, trace.BadParameter("expected at least valid principal in certificate") } - privateKey, err := ssh.ParseRawPrivateKey(c.sess.GetPriv()) + privateKey, err := ssh.ParseRawPrivateKey(c.session.GetPriv()) if err != nil { return nil, nil, trace.Wrap(err, "failed to parse SSH private key") } @@ -282,39 +280,101 @@ func (c *SessionContext) GetAgent() (agent.Agent, *ssh.Certificate, error) { } // GetCertificates returns the *ssh.Certificate and *x509.Certificate -// associated with this session. +// associated with this context's session. func (c *SessionContext) GetCertificates() (*ssh.Certificate, *x509.Certificate, error) { - pub, _, _, _, err := ssh.ParseAuthorizedKey(c.sess.GetPub()) + pub, _, _, _, err := ssh.ParseAuthorizedKey(c.session.GetPub()) if err != nil { return nil, nil, trace.Wrap(err) } - sshcert, ok := pub.(*ssh.Certificate) + sshCert, ok := pub.(*ssh.Certificate) if !ok { return nil, nil, trace.BadParameter("not certificate") } - tlscert, err := tlsca.ParseCertificatePEM(c.sess.GetTLSCert()) + tlsCert, err := tlsca.ParseCertificatePEM(c.session.GetTLSCert()) if err != nil { return nil, nil, trace.Wrap(err) } + return sshCert, tlsCert, nil - return sshcert, tlscert, nil } -// Close cleans up connections associated with requests +// GetSessionID returns the ID of the underlying user web session. +func (c *SessionContext) GetSessionID() string { + return c.session.GetName() +} + +// Close cleans up resources associated with this context and removes it +// from the user context func (c *SessionContext) Close() error { - closers := c.TransferClosers() - for _, closer := range closers { - c.Debugf("Closing %v.", closer) - closer.Close() + c.mu.Lock() + defer c.mu.Unlock() + var errors []error + for _, clt := range c.remoteClt { + if err := clt.Close(); err != nil { + errors = append(errors, err) + } } - if c.clt != nil { - return trace.Wrap(c.clt.Close()) + if err := c.clt.Close(); err != nil { + errors = append(errors, err) } - return nil + return trace.NewAggregate(errors...) +} + +// getToken returns the bearer token associated with the underlying +// session. Note that sessions are separate from bearer tokens and this +// is only useful immediately after a session has been created to query +// the token. +func (c *SessionContext) getToken() types.WebToken { + return types.NewWebToken(c.session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ + Token: c.session.GetBearerToken(), + }) +} + +// expired returns whether this context has expired. +// The context is considered expired when its bearer token TTL +// is in the past (subject to lingering threshold) +func (c *SessionContext) expired(ctx context.Context) bool { + _, err := c.parent.readSession(ctx, types.GetWebSessionRequest{ + User: c.user, + SessionID: c.session.GetName(), + }) + if err == nil { + return false + } + expiry := c.session.GetBearerTokenExpiryTime() + if expiry.IsZero() { + return false + } + if !trace.IsNotFound(err) { + c.log.WithError(err).Debug("Failed to query web session.") + } + // Give the session some time to linger so existing users of the context + // have successfully disposed of them. + // If we remove the session immediately, a stale copy might still use the + // cached site clients. + // This is a cheaper way to avoid race without introducing object + // reference counters. + return c.parent.clock.Since(expiry) > c.parent.sessionLingeringThreshold +} + +// cachedSessionLingeringThreshold specifies the maximum amount of time the session cache +// will hold onto a session before removing it. This period allows all outstanding references +// to disappear without fear of racing with the removal +const cachedSessionLingeringThreshold = 2 * time.Minute + +type sessionCacheOptions struct { + proxyClient auth.ClientI + accessPoint auth.ReadAccessPoint + servers []utils.NetAddr + cipherSuites []uint16 + clock clockwork.Clock + // sessionLingeringThreshold specifies the time the session will linger + // in the cache before getting purged after it has expired + sessionLingeringThreshold time.Duration } // newSessionCache returns new instance of the session cache -func newSessionCache(config *sessionCache) (*sessionCache, error) { +func newSessionCache(config sessionCacheOptions) (*sessionCache, error) { clusterName, err := config.proxyClient.GetClusterName() if err != nil { return nil, trace.Wrap(err) @@ -322,19 +382,18 @@ func newSessionCache(config *sessionCache) (*sessionCache, error) { if config.clock == nil { config.clock = clockwork.NewRealClock() } - m, err := ttlmap.New(1024, ttlmap.CallOnExpire(closeContext), ttlmap.Clock(config.clock)) - if err != nil { - return nil, trace.Wrap(err) - } cache := &sessionCache{ - clusterName: clusterName.GetClusterName(), - proxyClient: config.proxyClient, - contexts: m, - authServers: config.authServers, - closer: utils.NewCloseBroadcaster(), - cipherSuites: config.cipherSuites, - log: newPackageLogger(), - clock: config.clock, + clusterName: clusterName.GetClusterName(), + proxyClient: config.proxyClient, + accessPoint: config.accessPoint, + sessions: make(map[string]*SessionContext), + resources: make(map[string]*sessionResources), + authServers: config.servers, + closer: utils.NewCloseBroadcaster(), + cipherSuites: config.cipherSuites, + log: newPackageLogger(), + clock: config.clock, + sessionLingeringThreshold: config.sessionLingeringThreshold, } // periodically close expired and unused sessions go cache.expireSessions() @@ -342,19 +401,33 @@ func newSessionCache(config *sessionCache) (*sessionCache, error) { } // sessionCache handles web session authentication, -// and holds in memory contexts associated with each session +// and holds in-memory contexts associated with each session type sessionCache struct { - log logrus.FieldLogger - sync.Mutex + log logrus.FieldLogger proxyClient auth.ClientI - contexts *ttlmap.TTLMap authServers []utils.NetAddr + accessPoint auth.ReadAccessPoint closer *utils.CloseBroadcaster clusterName string clock clockwork.Clock - + // sessionLingeringThreshold specifies the time the session will linger + // in the cache before getting purged after it has expired + sessionLingeringThreshold time.Duration // cipherSuites is the list of supported TLS cipher suites. cipherSuites []uint16 + + mu sync.Mutex + // sessions maps user/sessionID to an active web session value between renewals. + // This is the client-facing session handle + sessions map[string]*SessionContext + + // session cache maintains a list of resources per-user as long + // as the user session is active even though individual session values + // are periodically recycled. + // Resources are disposed of when the corresponding session + // is either explicitly invalidated (e.g. during logout) or the + // resources are themselves closing + resources map[string]*sessionResources } // Close closes all allocated resources and stops goroutines @@ -363,46 +436,35 @@ func (s *sessionCache) Close() error { return s.closer.Close() } -// closeContext is called when session context expires from -// cache and will clean up connections -func closeContext(key string, val interface{}) { - go func() { - log.Infof("Closing context %v.", key) - ctx, ok := val.(*SessionContext) - if !ok { - log.Warnf("Invalid value type %T.", val) - return - } - if err := ctx.Close(); err != nil { - log.Warnf("Failed to close context: %v.", err) - } - }() -} - func (s *sessionCache) expireSessions() { - ticker := time.NewTicker(time.Second) + ticker := s.clock.NewTicker(1 * time.Second) defer ticker.Stop() for { select { - case <-ticker.C: - s.clearExpiredSessions() + case <-ticker.Chan(): + s.clearExpiredSessions(context.TODO()) case <-s.closer.C: return } } } -func (s *sessionCache) clearExpiredSessions() { - s.Lock() - defer s.Unlock() - expired := s.contexts.RemoveExpired(10) - if expired != 0 { - log.Infof("Removed %v expired sessions.", expired) +func (s *sessionCache) clearExpiredSessions(ctx context.Context) { + s.mu.Lock() + defer s.mu.Unlock() + for _, c := range s.sessions { + if !c.expired(ctx) { + continue + } + s.removeSessionContextLocked(c.session.GetUser(), c.session.GetName()) + s.log.WithField("ctx", c.String()).Debug("Context expired.") } } -func (s *sessionCache) AuthWithOTP(user, pass string, otpToken string) (services.WebSession, error) { +// AuthWithOTP authenticates the specified user with the given password and OTP token. +// Returns a new web session if successful. +func (s *sessionCache) AuthWithOTP(user, pass, otpToken string) (services.WebSession, error) { return s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{ Username: user, OTP: &auth.OTPCreds{ @@ -412,6 +474,8 @@ func (s *sessionCache) AuthWithOTP(user, pass string, otpToken string) (services }) } +// AuthWithoutOTP authenticates the specified user with the given password. +// Returns a new web session if successful. func (s *sessionCache) AuthWithoutOTP(user, pass string) (services.WebSession, error) { return s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{ Username: user, @@ -434,6 +498,7 @@ func (s *sessionCache) AuthWithU2FSignResponse(user string, response *u2f.Authen }) } +// GetCertificateWithoutOTP returns a new user certificate for the specified request. func (s *sessionCache) GetCertificateWithoutOTP(c client.CreateSSHCertReq) (*auth.SSHLoginResponse, error) { return s.proxyClient.AuthenticateSSHUser(auth.AuthenticateSSHRequest{ AuthenticateUserRequest: auth.AuthenticateUserRequest{ @@ -450,6 +515,8 @@ func (s *sessionCache) GetCertificateWithoutOTP(c client.CreateSSHCertReq) (*aut }) } +// GetCertificateWithOTP returns a new user certificate for the specified request. +// The request is used with the given OTP token. func (s *sessionCache) GetCertificateWithOTP(c client.CreateSSHCertReq) (*auth.SSHLoginResponse, error) { return s.proxyClient.AuthenticateSSHUser(auth.AuthenticateSSHRequest{ AuthenticateUserRequest: auth.AuthenticateUserRequest{ @@ -465,7 +532,6 @@ func (s *sessionCache) GetCertificateWithOTP(c client.CreateSSHCertReq) (*auth.S RouteToCluster: c.RouteToCluster, KubernetesCluster: c.KubernetesCluster, }) - } func (s *sessionCache) GetCertificateWithU2F(c client.CreateSSHCertWithU2FReq) (*auth.SSHLoginResponse, error) { @@ -497,70 +563,169 @@ func (s *sessionCache) ValidateTrustedCluster(validateRequest *auth.ValidateTrus return s.proxyClient.ValidateTrustedCluster(validateRequest) } -func (s *sessionCache) InvalidateSession(ctx *SessionContext) error { - defer ctx.Close() - if err := s.resetContext(ctx.GetUser(), ctx.GetWebSession().GetName()); err != nil { - return trace.Wrap(err) +// validateSession validates the session given with user and session ID. +// Returns a new or existing session context. +func (s *sessionCache) validateSession(ctx context.Context, user, sessionID string) (*SessionContext, error) { + sessionCtx, err := s.getContext(user, sessionID) + if err == nil { + return sessionCtx, nil } + if !trace.IsNotFound(err) { + return nil, trace.Wrap(err) + } + return s.newSessionContext(user, sessionID) +} + +func (s *sessionCache) invalidateSession(ctx *SessionContext) error { + defer ctx.Close() clt, err := ctx.GetClient() if err != nil { return trace.Wrap(err) } - err = clt.DeleteWebSession(ctx.GetUser(), ctx.GetWebSession().GetName()) - return trace.Wrap(err) -} - -func (s *sessionCache) getContext(user, sid string) (*SessionContext, error) { - s.Lock() - defer s.Unlock() - - val, ok := s.contexts.Get(user + sid) - if ok { - return val.(*SessionContext), nil + // Delete just the session - leave the bearer token to linger to avoid + // failing a client query still using the old token. + err = clt.WebSessions().Delete(context.TODO(), types.DeleteWebSessionRequest{ + User: ctx.user, + SessionID: ctx.session.GetName(), + }) + if err != nil && !trace.IsNotFound(err) { + return trace.Wrap(err) } - return nil, trace.NotFound("sessionContext not found") -} - -func (s *sessionCache) insertContext(user, sid string, ctx *SessionContext, ttl time.Duration) (*SessionContext, error) { - s.Lock() - defer s.Unlock() - - val, ok := s.contexts.Get(user + sid) - if ok && val != nil { // nil means that we've just invalidated the context now and set it to nil in the cache - return val.(*SessionContext), trace.AlreadyExists("exists") - } - if err := s.contexts.Set(user+sid, ctx, ttl); err != nil { - return nil, trace.Wrap(err) - } - return ctx, nil -} - -func (s *sessionCache) resetContext(user, sid string) error { - s.Lock() - defer s.Unlock() - context, ok := s.contexts.Remove(user + sid) - if ok { - closeContext(user+sid, context) + if err := s.releaseResources(ctx.GetUser(), ctx.session.GetName()); err != nil { + return trace.Wrap(err) } return nil } -func (s *sessionCache) ValidateSession(user, sid string) (*SessionContext, error) { - ctx, err := s.getContext(user, sid) - if err == nil { +func (s *sessionCache) getContext(user, sessionID string) (*SessionContext, error) { + s.mu.Lock() + defer s.mu.Unlock() + ctx, ok := s.sessions[user+sessionID] + if ok { return ctx, nil } + return nil, trace.NotFound("no context for user %v and session %v", + user, sessionID) +} - sess, err := s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{ +func (s *sessionCache) insertContext(user string, ctx *SessionContext) (exists bool) { + s.mu.Lock() + defer s.mu.Unlock() + id := sessionKey(user, ctx.session.GetName()) + if _, exists := s.sessions[id]; exists { + return true + } + s.sessions[id] = ctx + return false +} + +func (s *sessionCache) releaseResources(user, sessionID string) error { + s.mu.Lock() + defer s.mu.Unlock() + return s.releaseResourcesLocked(user, sessionID) +} + +func (s *sessionCache) removeSessionContextLocked(user, sessionID string) error { + id := sessionKey(user, sessionID) + ctx, ok := s.sessions[id] + if !ok { + return nil + } + delete(s.sessions, id) + err := ctx.Close() + if err != nil { + s.log.WithFields(logrus.Fields{ + "ctx": ctx.String(), + logrus.ErrorKey: err, + }).Warn("Failed to close session context.") + return trace.Wrap(err) + } + return nil +} + +func (s *sessionCache) releaseResourcesLocked(user, sessionID string) error { + var errors []error + err := s.removeSessionContextLocked(user, sessionID) + if err != nil { + errors = append(errors, err) + } + if ctx, ok := s.resources[user]; ok { + delete(s.resources, user) + if err := ctx.Close(); err != nil { + s.log.WithError(err).Warn("Failed to clean up session context.") + errors = append(errors, err) + } + } + return trace.NewAggregate(errors...) +} + +func (s *sessionCache) upsertSessionContext(user string) *sessionResources { + s.mu.Lock() + defer s.mu.Unlock() + if ctx, exists := s.resources[user]; exists { + return ctx + } + ctx := &sessionResources{ + log: s.log.WithFields(logrus.Fields{ + trace.Component: "user-session", + "user": user, + }), + } + s.resources[user] = ctx + return ctx +} + +// newSessionContext creates a new web session context for the specified user/session ID +func (s *sessionCache) newSessionContext(user, sessionID string) (*SessionContext, error) { + session, err := s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{ Username: user, Session: &auth.SessionCreds{ - ID: sid, + ID: sessionID, }, }) + if err != nil { + // This will fail if the session has expired and was removed + return nil, trace.Wrap(err) + } + return s.newSessionContextFromSession(session) +} + +func (s *sessionCache) newSessionContextFromSession(session services.WebSession) (*SessionContext, error) { + tlsConfig, err := s.tlsConfig(session.GetTLSCert(), session.GetPriv()) + if err != nil { + return nil, trace.Wrap(err) + } + userClient, err := auth.NewTLSClient(auth.ClientConfig{ + Addrs: s.authServers, + TLS: tlsConfig, + }) if err != nil { return nil, trace.Wrap(err) } + ctx := &SessionContext{ + clt: userClient, + remoteClt: make(map[string]auth.ClientI), + user: session.GetUser(), + session: session, + parent: s, + resources: s.upsertSessionContext(session.GetUser()), + log: s.log.WithFields(logrus.Fields{ + "user": session.GetUser(), + "session": session.GetShortName(), + }), + } + if err != nil { + return nil, trace.Wrap(err) + } + if exists := s.insertContext(session.GetUser(), ctx); exists { + // this means that someone has just inserted the context, so + // close our extra context and return + ctx.Close() + } + return ctx, nil +} +func (s *sessionCache) tlsConfig(cert, privKey []byte) (*tls.Config, error) { ca, err := s.proxyClient.GetCertAuthority(services.CertAuthID{ Type: services.HostCA, DomainName: s.clusterName, @@ -568,77 +733,133 @@ func (s *sessionCache) ValidateSession(user, sid string) (*SessionContext, error if err != nil { return nil, trace.Wrap(err) } - certPool, err := services.CertPool(ca) if err != nil { return nil, trace.Wrap(err) } tlsConfig := utils.TLSConfig(s.cipherSuites) - tlsCert, err := tls.X509KeyPair(sess.GetTLSCert(), sess.GetPriv()) + tlsCert, err := tls.X509KeyPair(cert, privKey) if err != nil { - return nil, trace.Wrap(err, "failed to parse TLS cert and key") + return nil, trace.Wrap(err, "failed to parse TLS certificate and key") } tlsConfig.Certificates = []tls.Certificate{tlsCert} tlsConfig.RootCAs = certPool tlsConfig.ServerName = auth.EncodeClusterName(s.clusterName) tlsConfig.Time = s.clock.Now + return tlsConfig, nil +} - userClient, err := auth.NewClient(apiclient.Config{ - Addrs: utils.NetAddrsToStrings(s.authServers), - TLS: tlsConfig, - }) - if err != nil { - return nil, trace.Wrap(err) +func (s *sessionCache) readSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { + // Read session from the cache first + session, err := s.accessPoint.GetWebSession(ctx, req) + if err == nil { + return session, nil } + // Fallback to proxy otherwise + return s.proxyClient.GetWebSession(ctx, req) +} - c := &SessionContext{ - clt: userClient, - remoteClt: make(map[string]auth.ClientI), - user: user, - sess: sess, - parent: s, - FieldLogger: log.WithFields(logrus.Fields{ - "user": user, - "sess": sess.GetShortName(), - }), +func (s *sessionCache) readBearerToken(ctx context.Context, req types.GetWebTokenRequest) (types.WebToken, error) { + // Read token from the cache first + token, err := s.accessPoint.GetWebToken(ctx, req) + if err == nil { + return token, nil } + // Fallback to proxy otherwise + return s.proxyClient.GetWebToken(ctx, req) +} - ttl := utils.ToTTL(s.clock, sess.GetBearerTokenExpiryTime()) - out, err := s.insertContext(user, sid, c, ttl) - if err != nil { - // this means that someone has just inserted the context, so - // close our extra context and return - if trace.IsAlreadyExists(err) { - defer c.Close() - return out, nil +// Close releases all underlying resources for the user session. +func (c *sessionResources) Close() error { + closers := c.transferClosers() + var errors []error + for _, closer := range closers { + c.log.Debugf("Closing %v.", closer) + if err := closer.Close(); err != nil { + errors = append(errors, err) } - return nil, trace.Wrap(err) } - return out, nil + return trace.NewAggregate(errors...) } -func (s *sessionCache) SetSession(w http.ResponseWriter, user, sid string) error { - d, err := EncodeCookie(user, sid) - if err != nil { - return err - } - c := &http.Cookie{ - Name: "session", - Value: d, - Path: "/", - HttpOnly: true, - Secure: true, - } - http.SetCookie(w, c) - return nil +// sessionResources persists resources initiated by a web session +// but which might outlive the session. +type sessionResources struct { + log logrus.FieldLogger + + mu sync.Mutex + closers []io.Closer } -func (s *sessionCache) ClearSession(w http.ResponseWriter) { - http.SetCookie(w, &http.Cookie{ - Name: "session", - Value: "", - Path: "/", - HttpOnly: true, - Secure: true, +// addClosers adds the specified closers to this context +func (c *sessionResources) addClosers(closers ...io.Closer) { + c.mu.Lock() + defer c.mu.Unlock() + c.closers = append(c.closers, closers...) +} + +// removeCloser removes the specified closer from this context +func (c *sessionResources) removeCloser(closer io.Closer) { + c.mu.Lock() + defer c.mu.Unlock() + for i, cls := range c.closers { + if cls == closer { + c.closers = append(c.closers[:i], c.closers[i+1:]...) + return + } + } +} + +func (c *sessionResources) transferClosers() []io.Closer { + c.mu.Lock() + defer c.mu.Unlock() + closers := c.closers + c.closers = nil + return closers +} + +func sessionKey(user, sessionID string) string { + return user + sessionID +} + +// waitForWebSession will block until the requested web session shows up in the +// cache or a timeout occurs. +func (h *Handler) waitForWebSession(ctx context.Context, req types.GetWebSessionRequest) error { + _, err := h.cfg.AccessPoint.GetWebSession(ctx, req) + if err == nil { + return nil + } + logger := h.log.WithField("req", req) + if !trace.IsNotFound(err) { + logger.WithError(err).Debug("Failed to query web session.") + } + // Establish a watch. + watcher, err := h.cfg.AccessPoint.NewWatcher(ctx, services.Watch{ + Name: teleport.ComponentWebProxy, + Kinds: []services.WatchKind{ + { + Kind: services.KindWebSession, + SubKind: services.KindWebSession, + }, + }, + MetricComponent: teleport.ComponentWebProxy, }) + if err != nil { + return trace.Wrap(err) + } + defer watcher.Close() + matchEvent := func(event services.Event) (services.Resource, error) { + if event.Type == backend.OpPut && + event.Resource.GetKind() == services.KindWebSession && + event.Resource.GetSubKind() == services.KindWebSession && + event.Resource.GetName() == req.SessionID { + return event.Resource, nil + } + return nil, trace.CompareFailed("no match") + } + _, err = local.WaitForEvent(ctx, watcher, local.EventMatcherFunc(matchEvent), h.clock) + if err != nil { + logger.WithError(err).Warn("Failed to wait for web session.") + } + return trace.Wrap(err) } diff --git a/lib/web/static.go b/lib/web/static.go index 1be9510d767..cdcd83f3fb9 100644 --- a/lib/web/static.go +++ b/lib/web/static.go @@ -24,18 +24,13 @@ import ( "os" "path" "path/filepath" - "strconv" "strings" - "github.com/gravitational/teleport" "github.com/gravitational/trace" "github.com/kardianos/osext" ) -// relative path to static assets. this is useful during development. -var debugAssetsPath string - const ( webAssetsMissingError = "the teleport binary was built without web assets, try building with `make release`" webAssetsReadError = "failure reading web assets from the binary" @@ -43,52 +38,41 @@ const ( // NewStaticFileSystem returns the initialized implementation of http.FileSystem // interface which can be used to serve Teleport Proxy Web UI -// -// If 'debugMode' is true, it will load the web assets from the same git repo -// directory where the executable is, otherwise it will load them from the embedded -// zip archive. -// -func NewStaticFileSystem(debugMode bool) (http.FileSystem, error) { - if debugMode { - assetsToCheck := []string{"index.html", "/app"} - - if debugAssetsPath == "" { - exePath, err := osext.ExecutableFolder() - if err != nil { - return nil, trace.Wrap(err) - } - - _, err = os.Stat(path.Join(exePath, "../../e")) - isEnterprise := !os.IsNotExist(err) - - if isEnterprise { - // enterprise web assets - debugAssetsPath = path.Join(exePath, "../../webassets/e/teleport") - } else { - // community web assets - debugAssetsPath = path.Join(exePath, "../webassets/teleport") - } - } - - for _, af := range assetsToCheck { - _, err := os.Stat(filepath.Join(debugAssetsPath, af)) - if err != nil { - return nil, trace.Wrap(err) - } - } - log.Infof("Using filesystem for serving web assets: %s.", debugAssetsPath) - return http.Dir(debugAssetsPath), nil - } - - // otherwise, lets use the zip archive attached to the executable: +func NewStaticFileSystem() (http.FileSystem, error) { + // Use the zip archive attached to the executable: return loadZippedExeAssets() } -// isDebugMode determines if teleport is running in a "debug" mode. -// It looks at DEBUG environment variable -func isDebugMode() bool { - v, _ := strconv.ParseBool(os.Getenv(teleport.DebugEnvVar)) - return v +// NewDebugFileSystem returns the HTTP file system implementation rooted +// at the specified assetsPath. +func NewDebugFileSystem(assetsPath string) (http.FileSystem, error) { + assetsToCheck := []string{"index.html", "/app"} + if assetsPath == "" { + exePath, err := osext.ExecutableFolder() + if err != nil { + return nil, trace.Wrap(err) + } + + _, err = os.Stat(path.Join(exePath, "../../e")) + isEnterprise := !os.IsNotExist(err) + + if isEnterprise { + // enterprise web assets + assetsPath = path.Join(exePath, "../../webassets/e/teleport") + } else { + // community web assets + assetsPath = path.Join(exePath, "../webassets/teleport") + } + } + + for _, af := range assetsToCheck { + _, err := os.Stat(filepath.Join(assetsPath, af)) + if err != nil { + return nil, trace.Wrap(err) + } + } + log.Infof("Using filesystem for serving web assets: %s.", assetsPath) + return http.Dir(assetsPath), nil } // LoadWebResources returns a filesystem implementation compatible diff --git a/lib/web/static_test.go b/lib/web/static_test.go index ae737708bcf..fa96a4f2452 100644 --- a/lib/web/static_test.go +++ b/lib/web/static_test.go @@ -19,11 +19,8 @@ package web import ( "io" "io/ioutil" - "os" "strings" - "github.com/gravitational/teleport" - "gopkg.in/check.v1" ) @@ -32,24 +29,8 @@ type StaticSuite struct { var _ = check.Suite(&StaticSuite{}) -func (s *StaticSuite) SetUpSuite(c *check.C) { - debugAssetsPath = "../../webassets/teleport" -} - -func (s *StaticSuite) TestDebugModeEnv(c *check.C) { - c.Assert(isDebugMode(), check.Equals, false) - os.Setenv(teleport.DebugEnvVar, "no") - c.Assert(isDebugMode(), check.Equals, false) - os.Setenv(teleport.DebugEnvVar, "0") - c.Assert(isDebugMode(), check.Equals, false) - os.Setenv(teleport.DebugEnvVar, "1") - c.Assert(isDebugMode(), check.Equals, true) - os.Setenv(teleport.DebugEnvVar, "true") - c.Assert(isDebugMode(), check.Equals, true) -} - func (s *StaticSuite) TestLocalFS(c *check.C) { - fs, err := NewStaticFileSystem(true) + fs, err := NewDebugFileSystem("../../webassets/teleport") c.Assert(err, check.IsNil) c.Assert(fs, check.NotNil) diff --git a/lib/web/terminal.go b/lib/web/terminal.go index baed8f9da28..feb0462838d 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -23,6 +23,7 @@ import ( "net/http" "strconv" "strings" + "sync" "time" "golang.org/x/crypto/ssh" @@ -85,7 +86,6 @@ type AuthProvider interface { // NewTerminal creates a web-based terminal based on WebSockets and returns a // new TerminalHandler. func NewTerminal(req TerminalRequest, authProvider AuthProvider, ctx *SessionContext) (*TerminalHandler, error) { - // Make sure whatever session is requested is a valid session. _, err := session.ParseID(string(req.SessionID)) if err != nil { @@ -173,6 +173,8 @@ type TerminalHandler struct { // buffer is a buffer used to store the remaining payload data if it did not // fit into the buffer provided by the callee to Read method buffer []byte + + closeOnce sync.Once } // Serve builds a connect to the remote node and then pumps back two types of @@ -197,20 +199,21 @@ func (t *TerminalHandler) Serve(w http.ResponseWriter, r *http.Request) { // Close the websocket stream. func (t *TerminalHandler) Close() error { - // Close the websocket connection to the client web browser. - if t.ws != nil { - t.ws.Close() - } + t.closeOnce.Do(func() { + // Close the websocket connection to the client web browser. + if t.ws != nil { + t.ws.Close() + } - // Close the SSH connection to the remote node. - if t.sshSession != nil { - t.sshSession.Close() - } - - // If the terminal handler was closed (most likely due to the *SessionContext - // closing) then the stream should be closed as well. - t.terminalCancel() + // Close the SSH connection to the remote node. + if t.sshSession != nil { + t.sshSession.Close() + } + // If the terminal handler was closed (most likely due to the *SessionContext + // closing) then the stream should be closed as well. + t.terminalCancel() + }) return nil } @@ -257,10 +260,7 @@ func (t *TerminalHandler) makeClient(ws *websocket.Conn) (*client.TeleportClient // Create a terminal stream that wraps/unwraps the envelope used to // communicate over the websocket. - stream, err := t.asTerminalStream(ws) - if err != nil { - return nil, trace.Wrap(err) - } + stream := t.asTerminalStream(ws) clientConfig.ForwardAgent = true clientConfig.HostLogin = t.params.Login @@ -595,14 +595,11 @@ func (t *TerminalHandler) read(out []byte, ws *websocket.Conn) (n int, err error } } -func (t *TerminalHandler) asTerminalStream(ws *websocket.Conn) (*terminalStream, error) { - if ws == nil { - return nil, trace.BadParameter("missing parameter ws") - } +func (t *TerminalHandler) asTerminalStream(ws *websocket.Conn) *terminalStream { return &terminalStream{ ws: ws, terminal: t, - }, nil + } } type terminalStream struct {