mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 17:23:22 +00:00
Fixes #5352 ```yaml allow: impersonate: users: ['alice', 'bob'] roles: ['*'] where: 'contains(user.spec.traits["groups"], impersonate_role.traits)' ``` Adds "impersonator" to all X.509 and SSH client certs issued using impersonation and does best effort to track requests by impersonators in audit events. Limits certs TTL to the impersonator's max session TTL. Prevents impersonating users to recursively impersonate other users. Allows impersonating users to renew their own certificate, for example to set route to cluster. Adds missing token permission for editor role.
This commit is contained in:
parent
854d5fc80b
commit
f17625c1a8
|
@ -129,7 +129,9 @@ type UserMetadata struct {
|
|||
// User is teleport user name
|
||||
User string `protobuf:"bytes,1,opt,name=User,proto3" json:"user"`
|
||||
// Login is OS login
|
||||
Login string `protobuf:"bytes,2,opt,name=Login,proto3" json:"login,omitempty"`
|
||||
Login string `protobuf:"bytes,2,opt,name=Login,proto3" json:"login,omitempty"`
|
||||
// Impersonator is a user acting on behalf of another user
|
||||
Impersonator string `protobuf:"bytes,3,opt,name=Impersonator,proto3" json:"impersonator,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
@ -3714,264 +3716,266 @@ func init() {
|
|||
func init() { proto.RegisterFile("events.proto", fileDescriptor_8f22242cb04491f9) }
|
||||
|
||||
var fileDescriptor_8f22242cb04491f9 = []byte{
|
||||
// 4108 bytes of a gzipped FileDescriptorProto
|
||||
// 4135 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3c, 0x4d, 0x6f, 0x1c, 0x47,
|
||||
0x76, 0xf3, 0xcd, 0x99, 0x37, 0x94, 0x44, 0x96, 0x28, 0xa9, 0x25, 0xcb, 0x6a, 0xa9, 0x65, 0xcb,
|
||||
0x54, 0x2c, 0x8b, 0x11, 0xcd, 0xb5, 0x36, 0x9b, 0x04, 0x36, 0x87, 0xa4, 0x76, 0x18, 0x53, 0x22,
|
||||
0x5d, 0xa4, 0x76, 0xf7, 0xb2, 0x1e, 0xf4, 0x4c, 0x97, 0xc8, 0x5e, 0xcd, 0x74, 0xcf, 0x76, 0xf7,
|
||||
0x50, 0xa2, 0x4f, 0xf9, 0xb8, 0xec, 0xc1, 0x01, 0x82, 0xcd, 0x29, 0xc8, 0x21, 0x01, 0x82, 0x1c,
|
||||
0x12, 0x04, 0x49, 0x90, 0x43, 0x90, 0xbb, 0xb3, 0x81, 0x81, 0x60, 0x93, 0xc5, 0xe6, 0x9c, 0x49,
|
||||
0x62, 0x20, 0x97, 0x01, 0xf2, 0x07, 0x82, 0x00, 0x59, 0xd4, 0xab, 0xea, 0xee, 0xea, 0x9e, 0x26,
|
||||
0x65, 0x89, 0x5a, 0x10, 0x94, 0x78, 0x23, 0xdf, 0x57, 0x75, 0xbd, 0x57, 0xf5, 0xaa, 0xde, 0x47,
|
||||
0x0d, 0x4c, 0xb2, 0x5d, 0xe6, 0x04, 0xfe, 0xed, 0xbe, 0xe7, 0x06, 0x2e, 0xa9, 0x88, 0xff, 0x2e,
|
||||
0xcd, 0x6c, 0xbb, 0xdb, 0x2e, 0x82, 0xe6, 0xf8, 0x5f, 0x02, 0x7b, 0x49, 0xdf, 0x76, 0xdd, 0xed,
|
||||
0x2e, 0x9b, 0xc3, 0xff, 0xda, 0x83, 0x47, 0x73, 0x81, 0xdd, 0x63, 0x7e, 0x60, 0xf6, 0xfa, 0x92,
|
||||
0xe0, 0x72, 0x9a, 0xc0, 0x0f, 0xbc, 0x41, 0x27, 0x10, 0x58, 0xe3, 0x47, 0x05, 0xa8, 0xde, 0x67,
|
||||
0x81, 0x69, 0x99, 0x81, 0x49, 0x2e, 0x43, 0x79, 0xd5, 0xb1, 0xd8, 0x53, 0x2d, 0x7f, 0x35, 0x3f,
|
||||
0x5b, 0x6c, 0x54, 0x46, 0x43, 0xbd, 0xc0, 0x6c, 0x2a, 0x80, 0xe4, 0x4d, 0x28, 0x6d, 0xed, 0xf5,
|
||||
0x99, 0x56, 0xb8, 0x9a, 0x9f, 0xad, 0x35, 0x6a, 0xa3, 0xa1, 0x5e, 0xc6, 0x2f, 0xa3, 0x08, 0x26,
|
||||
0xd7, 0xa0, 0xb0, 0xba, 0xac, 0x15, 0x11, 0x39, 0x3d, 0x1a, 0xea, 0xa7, 0x06, 0xb6, 0x75, 0xcb,
|
||||
0xed, 0xd9, 0x01, 0xeb, 0xf5, 0x83, 0x3d, 0x5a, 0x58, 0x5d, 0x26, 0x37, 0xa0, 0xb4, 0xe4, 0x5a,
|
||||
0x4c, 0x2b, 0x21, 0x11, 0x19, 0x0d, 0xf5, 0xd3, 0x1d, 0xd7, 0x62, 0x0a, 0x15, 0xe2, 0xc9, 0x47,
|
||||
0x50, 0xda, 0xb2, 0x7b, 0x4c, 0x2b, 0x5f, 0xcd, 0xcf, 0xd6, 0xe7, 0x2f, 0xdd, 0x16, 0x33, 0xb8,
|
||||
0x1d, 0xce, 0xe0, 0xf6, 0x56, 0x38, 0xc5, 0xc6, 0xd4, 0x97, 0x43, 0x3d, 0x37, 0x1a, 0xea, 0x25,
|
||||
0x3e, 0xeb, 0x3f, 0xf8, 0x0f, 0x3d, 0x4f, 0x91, 0x93, 0xcc, 0x43, 0x7d, 0xa9, 0x3b, 0xf0, 0x03,
|
||||
0xe6, 0x3d, 0x30, 0x7b, 0x4c, 0xab, 0xe0, 0x80, 0x53, 0xa3, 0xa1, 0x3e, 0xd9, 0x11, 0xe0, 0x96,
|
||||
0x63, 0xf6, 0x18, 0x55, 0x89, 0x8c, 0x1f, 0xc0, 0x99, 0x4d, 0xe6, 0xfb, 0xb6, 0xeb, 0x44, 0x0a,
|
||||
0x79, 0x1b, 0x6a, 0x12, 0xb4, 0xba, 0x8c, 0x4a, 0xa9, 0x35, 0x26, 0x46, 0x43, 0xbd, 0xe8, 0xdb,
|
||||
0x16, 0x8d, 0x31, 0xe4, 0x57, 0x61, 0xe2, 0xbb, 0x76, 0xb0, 0x73, 0xff, 0xde, 0xa2, 0x54, 0xce,
|
||||
0xf9, 0xd1, 0x50, 0x27, 0x4f, 0xec, 0x60, 0xa7, 0xd5, 0x7b, 0x64, 0x2a, 0xd3, 0x0b, 0xc9, 0x8c,
|
||||
0xef, 0xc2, 0xe4, 0x43, 0x9f, 0x79, 0x8a, 0xe6, 0x4b, 0xfc, 0x7f, 0x39, 0x46, 0x95, 0xcf, 0x68,
|
||||
0xe0, 0x33, 0x8f, 0x22, 0x94, 0xdc, 0x84, 0xf2, 0x9a, 0xbb, 0x6d, 0x3b, 0x52, 0xfa, 0xd9, 0xd1,
|
||||
0x50, 0x3f, 0xd3, 0xe5, 0x00, 0x45, 0xb4, 0xa0, 0x30, 0xfe, 0xb6, 0x08, 0xa7, 0x37, 0x99, 0xb7,
|
||||
0xab, 0xc8, 0x5e, 0xe4, 0xf3, 0xe2, 0x10, 0x3e, 0x4b, 0xbf, 0x6f, 0x76, 0x98, 0x1c, 0xe6, 0xc2,
|
||||
0x68, 0xa8, 0x9f, 0x75, 0x42, 0xa0, 0x22, 0x2b, 0x4d, 0x4f, 0x6e, 0x42, 0x55, 0x80, 0x56, 0x97,
|
||||
0xe5, 0x37, 0x9c, 0x1a, 0x0d, 0xf5, 0x9a, 0x8f, 0xb0, 0x96, 0x6d, 0xd1, 0x08, 0x4d, 0x56, 0xc2,
|
||||
0xf1, 0x9b, 0xae, 0x1f, 0x70, 0xe1, 0x72, 0x49, 0xbc, 0x39, 0x1a, 0xea, 0x17, 0x25, 0xc3, 0x8e,
|
||||
0x44, 0x29, 0x43, 0xa6, 0x98, 0xc8, 0xaf, 0x01, 0x08, 0xc8, 0xa2, 0x65, 0x79, 0x72, 0xc1, 0x5c,
|
||||
0x1c, 0x0d, 0xf5, 0x73, 0x52, 0x84, 0x69, 0x59, 0x9e, 0xc2, 0xae, 0x10, 0x93, 0x1e, 0x4c, 0x8a,
|
||||
0xff, 0xd6, 0xcc, 0x36, 0xeb, 0xfa, 0x5a, 0xf9, 0x6a, 0x71, 0xb6, 0x3e, 0x3f, 0x7b, 0x5b, 0x6e,
|
||||
0xaa, 0xa4, 0x76, 0x6e, 0xab, 0xa4, 0x2b, 0x4e, 0xe0, 0xed, 0x35, 0x74, 0xb9, 0xa6, 0x2e, 0xc8,
|
||||
0xa1, 0xba, 0x88, 0x53, 0x06, 0x4b, 0x88, 0xbf, 0xf4, 0x21, 0x4c, 0x8f, 0xc9, 0x20, 0x53, 0x50,
|
||||
0x7c, 0xcc, 0xf6, 0x84, 0x9e, 0x29, 0xff, 0x93, 0xcc, 0x40, 0x79, 0xd7, 0xec, 0x0e, 0xe4, 0xf6,
|
||||
0xa1, 0xe2, 0x9f, 0x6f, 0x15, 0xbe, 0x99, 0x37, 0xfe, 0x21, 0x0f, 0x64, 0xc9, 0x75, 0x1c, 0xd6,
|
||||
0x09, 0xd4, 0xb5, 0xf7, 0x01, 0xd4, 0xd6, 0xdc, 0x8e, 0xd9, 0x45, 0x05, 0x08, 0x83, 0x69, 0xa3,
|
||||
0xa1, 0x3e, 0xc3, 0x67, 0x7e, 0xbb, 0xcb, 0x31, 0xca, 0x27, 0xc5, 0xa4, 0x5c, 0x73, 0x94, 0xf5,
|
||||
0xdc, 0x80, 0x21, 0x63, 0x21, 0xd6, 0x1c, 0x32, 0x7a, 0x88, 0x52, 0x35, 0x17, 0x13, 0x93, 0x39,
|
||||
0xa8, 0x6e, 0xf0, 0x3d, 0xd6, 0x71, 0xbb, 0xd2, 0x6a, 0xb8, 0xd4, 0x70, 0xdf, 0x29, 0x2c, 0x11,
|
||||
0x91, 0xf1, 0xbb, 0x05, 0xb8, 0xf8, 0xf1, 0xa0, 0xcd, 0x3c, 0x87, 0x05, 0xcc, 0x97, 0x9b, 0x29,
|
||||
0x9a, 0xc1, 0x03, 0x98, 0x1e, 0x43, 0xca, 0x99, 0x5c, 0x1d, 0x0d, 0xf5, 0xcb, 0x8f, 0x23, 0x64,
|
||||
0x4b, 0xee, 0x4a, 0x65, 0x90, 0x71, 0x56, 0xd2, 0x84, 0x33, 0x31, 0x90, 0x6f, 0x0c, 0x5f, 0x2b,
|
||||
0x5c, 0x2d, 0xce, 0xd6, 0x1a, 0x57, 0x46, 0x43, 0xfd, 0x92, 0x22, 0x8d, 0x6f, 0x1d, 0xd5, 0x60,
|
||||
0x69, 0x36, 0xf2, 0x31, 0x4c, 0xc5, 0xa0, 0x6f, 0x7b, 0xee, 0xa0, 0xef, 0x6b, 0x45, 0x14, 0xa5,
|
||||
0x8f, 0x86, 0xfa, 0x1b, 0x8a, 0xa8, 0x6d, 0x44, 0x2a, 0xb2, 0xc6, 0x18, 0x8d, 0xff, 0x2e, 0xc2,
|
||||
0xb9, 0x18, 0xb8, 0xe1, 0x5a, 0x91, 0x02, 0xd6, 0x55, 0x05, 0x6c, 0xb8, 0x16, 0xfa, 0x22, 0xa1,
|
||||
0x80, 0x6b, 0xa3, 0xa1, 0xfe, 0xa6, 0x32, 0x4e, 0xdf, 0xb5, 0x5a, 0xa9, 0x2d, 0x31, 0xce, 0x4b,
|
||||
0x3e, 0x85, 0xf3, 0x63, 0x40, 0xb1, 0xa3, 0x85, 0x9d, 0x6f, 0x8c, 0x86, 0xba, 0x91, 0x21, 0x35,
|
||||
0xbd, 0xc1, 0xf7, 0x91, 0x42, 0x4c, 0xb8, 0xa0, 0xa8, 0xdd, 0x75, 0x02, 0xd3, 0x76, 0xa4, 0x0b,
|
||||
0x15, 0xeb, 0xe1, 0x9d, 0xd1, 0x50, 0xbf, 0xae, 0xda, 0x2d, 0xa4, 0x49, 0x7f, 0xfc, 0x7e, 0x72,
|
||||
0x88, 0x05, 0x5a, 0x06, 0x6a, 0xb5, 0x67, 0x6e, 0x87, 0xe7, 0xc2, 0xec, 0x68, 0xa8, 0xbf, 0x95,
|
||||
0x39, 0x86, 0xcd, 0xa9, 0x94, 0x41, 0xf6, 0x95, 0x44, 0x28, 0x90, 0x18, 0xf7, 0xc0, 0xb5, 0x18,
|
||||
0xce, 0xa1, 0x8c, 0xf2, 0x8d, 0xd1, 0x50, 0xbf, 0xa2, 0xc8, 0x77, 0x5c, 0x8b, 0xa5, 0x3f, 0x3f,
|
||||
0x83, 0xdb, 0xf8, 0xbf, 0x12, 0x77, 0x2c, 0xe8, 0xf3, 0x37, 0x03, 0xd3, 0x0b, 0xc8, 0xb7, 0xe2,
|
||||
0xa3, 0x13, 0xad, 0x5a, 0x9f, 0x9f, 0x0a, 0x9d, 0x4c, 0x08, 0x6f, 0x4c, 0x72, 0x67, 0xf2, 0xb3,
|
||||
0xa1, 0x9e, 0x1f, 0x0d, 0xf5, 0x1c, 0xad, 0x2a, 0xbb, 0x5b, 0x38, 0xfc, 0x02, 0xf2, 0xcd, 0x84,
|
||||
0x7c, 0xea, 0xa1, 0x90, 0xe2, 0x15, 0x47, 0xc1, 0x87, 0x30, 0x21, 0xbf, 0x01, 0x2d, 0x52, 0x9f,
|
||||
0xbf, 0x10, 0xfb, 0xb5, 0xc4, 0xd9, 0x95, 0xe2, 0x0e, 0xb9, 0xc8, 0x6f, 0x40, 0x45, 0xb8, 0x2b,
|
||||
0xd4, 0x76, 0x7d, 0xfe, 0x7c, 0xb6, 0x5f, 0x4c, 0xb1, 0x4b, 0x1e, 0xd2, 0x04, 0x88, 0x5d, 0x55,
|
||||
0x74, 0x3e, 0x4b, 0x09, 0xe3, 0x4e, 0x2c, 0x25, 0x45, 0xe1, 0x25, 0x1f, 0xc0, 0xe4, 0x16, 0xf3,
|
||||
0x7a, 0xb6, 0x63, 0x76, 0x37, 0xed, 0xcf, 0xc2, 0x23, 0x1a, 0xef, 0x04, 0xbe, 0xfd, 0x99, 0x6a,
|
||||
0x8b, 0x04, 0x1d, 0xf9, 0x7e, 0x96, 0x53, 0x99, 0xc0, 0x0f, 0xb9, 0x16, 0x7e, 0xc8, 0xbe, 0x2e,
|
||||
0x29, 0xf5, 0x3d, 0x19, 0x3e, 0xe6, 0x13, 0x38, 0x95, 0xd8, 0x1b, 0x5a, 0x15, 0x45, 0xbf, 0x39,
|
||||
0x2e, 0x5a, 0xd9, 0xe8, 0x29, 0xb1, 0x49, 0x09, 0xfc, 0x44, 0x5c, 0x75, 0xec, 0xc0, 0x36, 0xbb,
|
||||
0x4b, 0x6e, 0xaf, 0x67, 0x3a, 0x96, 0x56, 0x43, 0x57, 0x83, 0x27, 0xa2, 0x2d, 0x30, 0xad, 0x8e,
|
||||
0x40, 0xa9, 0x27, 0x62, 0x92, 0xc9, 0xf8, 0x8b, 0x22, 0xd4, 0xa5, 0x11, 0x7f, 0xcb, 0xb5, 0x9d,
|
||||
0x93, 0xd5, 0x77, 0x98, 0xd5, 0x97, 0xb9, 0x8a, 0x2a, 0x2f, 0x6b, 0x15, 0x19, 0x9f, 0x17, 0x22,
|
||||
0x57, 0xb1, 0xe1, 0xd9, 0xce, 0xe1, 0x5c, 0xc5, 0x0d, 0x80, 0xa5, 0x9d, 0x81, 0xf3, 0x58, 0x5c,
|
||||
0xcd, 0x0b, 0xf1, 0xd5, 0xbc, 0x63, 0x53, 0x05, 0xc3, 0xef, 0xe7, 0xcb, 0x5c, 0x3e, 0xb7, 0xcc,
|
||||
0x64, 0xa3, 0xf6, 0xa5, 0x90, 0x94, 0x7f, 0x8f, 0x22, 0x98, 0xe8, 0x50, 0x6e, 0xec, 0x05, 0xcc,
|
||||
0x47, 0xcd, 0x17, 0xc5, 0xfd, 0xbd, 0xcd, 0x01, 0x54, 0xc0, 0xc9, 0x02, 0x4c, 0x2f, 0xb3, 0xae,
|
||||
0xb9, 0x77, 0xdf, 0xee, 0x76, 0x6d, 0x9f, 0x75, 0x5c, 0xc7, 0xf2, 0x51, 0xc9, 0x72, 0xb8, 0x9e,
|
||||
0x4f, 0xc7, 0x09, 0x88, 0x01, 0x95, 0xf5, 0x47, 0x8f, 0x7c, 0x16, 0xa0, 0xfa, 0x8a, 0x0d, 0x18,
|
||||
0x0d, 0xf5, 0x8a, 0x8b, 0x10, 0x2a, 0x31, 0xc6, 0xcf, 0x0b, 0x70, 0x4a, 0xaa, 0x83, 0xb2, 0x1f,
|
||||
0xb0, 0xce, 0xd1, 0xb8, 0xce, 0x78, 0xed, 0x15, 0x0f, 0xbd, 0xf6, 0x4a, 0x87, 0x58, 0x7b, 0x06,
|
||||
0x54, 0x28, 0x33, 0x7d, 0xb9, 0x82, 0x6b, 0x42, 0x63, 0x1e, 0x42, 0xa8, 0xc4, 0x90, 0x6b, 0x30,
|
||||
0x71, 0xdf, 0x7c, 0x6a, 0xf7, 0x06, 0x3d, 0xa9, 0x56, 0x0c, 0x3b, 0x7a, 0xe6, 0x53, 0x1a, 0xc2,
|
||||
0x8d, 0xbf, 0x29, 0x71, 0x39, 0xdc, 0x57, 0x1e, 0x4f, 0x57, 0xf0, 0xf2, 0x14, 0x1a, 0x1b, 0xb6,
|
||||
0xfc, 0x02, 0x86, 0x7d, 0x6d, 0x0e, 0x22, 0xe3, 0x2f, 0x27, 0x78, 0x50, 0x85, 0xda, 0x5f, 0x71,
|
||||
0xac, 0x93, 0x55, 0x73, 0x98, 0x55, 0xb3, 0x0c, 0xd3, 0x2b, 0xce, 0x8e, 0xe9, 0x74, 0x98, 0x45,
|
||||
0x59, 0xc7, 0xf5, 0x2c, 0xdb, 0xd9, 0xc6, 0xa5, 0x53, 0x15, 0xc1, 0x3f, 0x93, 0xc8, 0x96, 0x17,
|
||||
0x62, 0xe9, 0x38, 0x03, 0xb9, 0x03, 0xf5, 0x55, 0x27, 0x60, 0x9e, 0xd9, 0x09, 0xec, 0x5d, 0x86,
|
||||
0xab, 0xa7, 0xda, 0x38, 0x33, 0x1a, 0xea, 0x75, 0x3b, 0x06, 0x53, 0x95, 0x86, 0x2c, 0xc0, 0xe4,
|
||||
0x86, 0xe9, 0x05, 0x76, 0xc7, 0xee, 0x9b, 0x4e, 0xe0, 0x6b, 0x55, 0xbc, 0x4b, 0x60, 0x6a, 0xa3,
|
||||
0xaf, 0xc0, 0x69, 0x82, 0x8a, 0x7c, 0x1f, 0x6a, 0x78, 0x67, 0xc5, 0xb4, 0x4a, 0xed, 0x99, 0x69,
|
||||
0x95, 0xeb, 0x71, 0x08, 0x8c, 0x6a, 0x6f, 0xf9, 0x9c, 0x39, 0xde, 0x0a, 0x98, 0x69, 0x89, 0x25,
|
||||
0x92, 0xef, 0xc1, 0xc4, 0x8a, 0x63, 0xa1, 0x70, 0x78, 0xa6, 0x70, 0x43, 0x0a, 0x3f, 0x1f, 0x0b,
|
||||
0x77, 0xfb, 0x29, 0xd9, 0xa1, 0xb8, 0xec, 0x5d, 0x56, 0xff, 0xe5, 0xed, 0xb2, 0xc9, 0x5f, 0xc2,
|
||||
0x75, 0xef, 0xd4, 0x8b, 0x5c, 0xf7, 0x3e, 0x83, 0x7a, 0x63, 0xe3, 0x5e, 0xb4, 0xe1, 0x2e, 0x42,
|
||||
0x71, 0x43, 0xe6, 0xa0, 0x4a, 0xe2, 0x30, 0xe8, 0xdb, 0x16, 0xe5, 0x30, 0x72, 0x13, 0xaa, 0x4b,
|
||||
0x18, 0xa6, 0xca, 0xe4, 0x4c, 0x49, 0x24, 0x67, 0x3a, 0x08, 0xc3, 0xe4, 0x4c, 0x88, 0x26, 0x6f,
|
||||
0xc3, 0xc4, 0x86, 0xe7, 0x6e, 0x7b, 0x66, 0x4f, 0xc6, 0x73, 0xf5, 0xd1, 0x50, 0x9f, 0xe8, 0x0b,
|
||||
0x10, 0x0d, 0x71, 0xc6, 0x1f, 0xe6, 0xa1, 0xb2, 0x19, 0x98, 0xc1, 0xc0, 0xe7, 0x1c, 0x9b, 0x83,
|
||||
0x4e, 0x87, 0xf9, 0x3e, 0x8e, 0x5d, 0x15, 0x1c, 0xbe, 0x00, 0xd1, 0x10, 0x47, 0x6e, 0x42, 0x79,
|
||||
0xc5, 0xf3, 0x5c, 0x4f, 0xcd, 0x50, 0x31, 0x0e, 0x50, 0x33, 0x54, 0x48, 0x41, 0xee, 0x42, 0x5d,
|
||||
0xb8, 0x09, 0xdf, 0xe7, 0x31, 0x9f, 0xf8, 0x8e, 0x73, 0xa3, 0xa1, 0x3e, 0xdd, 0x13, 0x20, 0x85,
|
||||
0x45, 0xa5, 0x34, 0xbe, 0xc0, 0xd4, 0x16, 0x2e, 0x19, 0xa9, 0xa4, 0xd7, 0xf1, 0x0e, 0xfc, 0x3e,
|
||||
0x14, 0x1b, 0x1b, 0xf7, 0xa4, 0xcf, 0x3a, 0x1b, 0xb2, 0x2a, 0x4b, 0x25, 0xc5, 0xc7, 0xa9, 0xc9,
|
||||
0x65, 0x28, 0x6d, 0xf0, 0xe5, 0x53, 0xc1, 0xe5, 0x81, 0xe9, 0xc5, 0x3e, 0x5f, 0x3f, 0x08, 0x45,
|
||||
0xac, 0x19, 0xec, 0xa0, 0xfb, 0x91, 0xc9, 0xc7, 0xbe, 0x19, 0xec, 0x50, 0x84, 0x72, 0xec, 0xa2,
|
||||
0xb7, 0xbd, 0x2b, 0x1d, 0x0d, 0x62, 0x4d, 0x6f, 0x7b, 0x97, 0x22, 0x94, 0xcc, 0x01, 0x50, 0x16,
|
||||
0x0c, 0x3c, 0x07, 0x13, 0xbb, 0xdc, 0xb3, 0x94, 0x85, 0x03, 0xf3, 0x10, 0xda, 0xea, 0xb8, 0x16,
|
||||
0xa3, 0x0a, 0x89, 0xf1, 0xe7, 0x71, 0x18, 0xb3, 0x6c, 0xfb, 0x8f, 0x4f, 0x4c, 0xf8, 0x1c, 0x26,
|
||||
0xe4, 0x46, 0xaa, 0x64, 0x1a, 0x49, 0x87, 0xf2, 0xbd, 0xae, 0xb9, 0xed, 0xa3, 0x0d, 0xcb, 0xe2,
|
||||
0x72, 0xff, 0x88, 0x03, 0xa8, 0x80, 0xa7, 0xec, 0x54, 0x7d, 0xb6, 0x9d, 0xfe, 0x3d, 0xde, 0x6d,
|
||||
0x0f, 0x58, 0xf0, 0xc4, 0xf5, 0x4e, 0x4c, 0xf5, 0x75, 0x4d, 0x75, 0x03, 0x26, 0x36, 0xbd, 0x0e,
|
||||
0xa6, 0x5f, 0x85, 0xb5, 0x26, 0x47, 0x43, 0xbd, 0xea, 0x7b, 0x1d, 0xcc, 0x5a, 0xd3, 0x10, 0xc9,
|
||||
0xe9, 0x96, 0xfd, 0x00, 0xe9, 0x26, 0x62, 0x3a, 0xcb, 0x0f, 0x24, 0x9d, 0x44, 0x4a, 0xba, 0x0d,
|
||||
0xd7, 0x0b, 0xa4, 0xe1, 0x22, 0xba, 0xbe, 0xeb, 0x05, 0x34, 0x44, 0x92, 0x77, 0x01, 0xb6, 0x96,
|
||||
0x36, 0xbe, 0xc3, 0x3c, 0x54, 0x97, 0xd8, 0x8b, 0xe8, 0xae, 0x77, 0x05, 0x88, 0x2a, 0x68, 0xe3,
|
||||
0xaf, 0x94, 0x7d, 0xc8, 0x0d, 0x74, 0x92, 0x4e, 0x38, 0xc4, 0x5d, 0x72, 0x1e, 0xa6, 0x30, 0x86,
|
||||
0xde, 0xf2, 0x4c, 0xc7, 0xef, 0xd9, 0x41, 0xc0, 0x2c, 0xe9, 0x6b, 0x31, 0x72, 0x0e, 0x9e, 0xd2,
|
||||
0x31, 0x3c, 0xb9, 0x05, 0xa7, 0x10, 0x46, 0x59, 0x87, 0xd9, 0xbb, 0xcc, 0xc2, 0x35, 0x20, 0x19,
|
||||
0xbc, 0xa7, 0x34, 0x89, 0x34, 0xfe, 0x39, 0xce, 0x28, 0xac, 0x31, 0x73, 0x97, 0x9d, 0xd8, 0xeb,
|
||||
0x10, 0xf6, 0x32, 0xfe, 0xac, 0x08, 0x35, 0x3e, 0x23, 0xac, 0x99, 0x1d, 0x89, 0x2a, 0x17, 0xc2,
|
||||
0x1b, 0x96, 0xd4, 0xe4, 0xe9, 0x48, 0x13, 0x08, 0x1d, 0xd3, 0x80, 0xb8, 0x8d, 0xdd, 0x82, 0xca,
|
||||
0x7d, 0x16, 0xec, 0xb8, 0x96, 0x4c, 0x95, 0xcf, 0x8c, 0x86, 0xfa, 0x54, 0x0f, 0x21, 0xca, 0xad,
|
||||
0x49, 0xd2, 0x90, 0xc7, 0x40, 0x56, 0x2d, 0xe6, 0x04, 0x76, 0xb0, 0xb7, 0x18, 0x04, 0x9e, 0xdd,
|
||||
0x1e, 0x04, 0xcc, 0x97, 0x7a, 0xbb, 0x30, 0x76, 0x41, 0xdf, 0xc4, 0xb2, 0x30, 0x66, 0xc7, 0x67,
|
||||
0xcc, 0x88, 0x3c, 0x16, 0xfb, 0xbf, 0x43, 0xbd, 0x22, 0x68, 0x68, 0x86, 0x58, 0xf2, 0x09, 0xd4,
|
||||
0xee, 0xdf, 0x5b, 0x5c, 0x66, 0xbb, 0x76, 0x87, 0xc9, 0x4c, 0xda, 0xc5, 0x48, 0x8b, 0x21, 0x22,
|
||||
0x52, 0x09, 0x56, 0xb2, 0x7a, 0x8f, 0xcc, 0x96, 0x85, 0x70, 0xb5, 0x92, 0x15, 0x11, 0x1b, 0x5f,
|
||||
0xe5, 0x61, 0x8a, 0x32, 0xdf, 0x1d, 0x78, 0x31, 0x27, 0xb9, 0x01, 0x25, 0xa5, 0x8c, 0x82, 0x61,
|
||||
0x7a, 0x2a, 0x77, 0x8f, 0x78, 0xb2, 0x0a, 0x13, 0x2b, 0x4f, 0xfb, 0xb6, 0xc7, 0x7c, 0x69, 0x9b,
|
||||
0x83, 0x42, 0x92, 0xb3, 0x32, 0x24, 0x99, 0x60, 0x82, 0x45, 0xc6, 0x20, 0xe2, 0x1f, 0xf2, 0x01,
|
||||
0xd4, 0x1e, 0xf6, 0x2d, 0x33, 0x60, 0x56, 0x63, 0x4f, 0xde, 0x57, 0xf1, 0xfb, 0x07, 0x02, 0xd8,
|
||||
0x6a, 0xef, 0xa9, 0xdf, 0x1f, 0x91, 0x92, 0xeb, 0x50, 0xdc, 0xda, 0x5a, 0x93, 0xa6, 0xc2, 0x92,
|
||||
0x78, 0x10, 0xa8, 0x45, 0x3b, 0x8e, 0x35, 0x7e, 0x5c, 0x00, 0xe0, 0x2b, 0x62, 0xc9, 0x63, 0x66,
|
||||
0x70, 0x34, 0xdb, 0xba, 0x01, 0xd5, 0x50, 0xcd, 0x72, 0x35, 0x6a, 0x21, 0x6f, 0x5a, 0xfd, 0xe9,
|
||||
0xb1, 0x43, 0x3c, 0xbf, 0x80, 0x50, 0xb7, 0x8b, 0xd9, 0xc5, 0x62, 0xd8, 0x1d, 0xe0, 0x71, 0x00,
|
||||
0x15, 0x70, 0xf2, 0x2e, 0xd4, 0xe4, 0x06, 0x74, 0x3d, 0x99, 0xf8, 0x12, 0x61, 0x4a, 0x08, 0xa4,
|
||||
0x31, 0xde, 0xf8, 0xc7, 0xbc, 0x50, 0xca, 0x32, 0xeb, 0xb2, 0xe3, 0xab, 0x14, 0xe3, 0x47, 0x79,
|
||||
0x20, 0x5c, 0xd8, 0x86, 0xe9, 0xfb, 0x4f, 0x5c, 0xcf, 0x5a, 0xda, 0x31, 0x9d, 0xed, 0x23, 0x99,
|
||||
0x8e, 0xf1, 0xe3, 0x12, 0x9c, 0x5d, 0x14, 0x41, 0x1b, 0xfb, 0xe1, 0x80, 0xf9, 0xc1, 0x31, 0x5f,
|
||||
0x6f, 0x37, 0x93, 0xeb, 0x0d, 0x03, 0x4e, 0x5c, 0x6f, 0x6a, 0xc0, 0x29, 0x56, 0xde, 0x5b, 0x50,
|
||||
0x93, 0x73, 0x5e, 0x5d, 0x96, 0x2b, 0x0f, 0x0f, 0x59, 0xdb, 0xa2, 0x31, 0x82, 0xbc, 0x07, 0x93,
|
||||
0xf2, 0x1f, 0xee, 0x6b, 0xc3, 0x34, 0x20, 0xae, 0x63, 0x9f, 0x03, 0x68, 0x02, 0x4d, 0xbe, 0x01,
|
||||
0x35, 0xbe, 0x38, 0xb7, 0x4d, 0xbe, 0x9c, 0x27, 0xe2, 0x76, 0x0a, 0x2b, 0x04, 0xaa, 0x2e, 0x21,
|
||||
0xa2, 0xe4, 0x0e, 0x5c, 0xe6, 0x7e, 0xab, 0xb1, 0x03, 0x17, 0xb9, 0x5f, 0xd5, 0x81, 0xcb, 0x2c,
|
||||
0xf0, 0xa7, 0x50, 0x5f, 0x74, 0x1c, 0x37, 0x30, 0xf9, 0xa1, 0xe5, 0xcb, 0xbc, 0xcd, 0xbe, 0x9e,
|
||||
0xfb, 0x3a, 0x16, 0xf9, 0x63, 0xfa, 0x4c, 0xd7, 0xad, 0x0a, 0x34, 0xfe, 0xa4, 0x00, 0x75, 0x7e,
|
||||
0x73, 0xbc, 0xe7, 0x7a, 0x4f, 0x4c, 0xef, 0x68, 0xc2, 0xe9, 0xe4, 0xa1, 0x5e, 0x3c, 0xc4, 0x25,
|
||||
0x2c, 0x3e, 0x52, 0x4b, 0xcf, 0x71, 0xa4, 0xf2, 0xf0, 0x96, 0xdf, 0xc0, 0xcb, 0x71, 0x5c, 0x85,
|
||||
0xb7, 0x6f, 0x84, 0x1a, 0xbf, 0x5d, 0x00, 0xf8, 0xde, 0x9d, 0x3b, 0xaf, 0xb1, 0x82, 0x8c, 0x3f,
|
||||
0xce, 0xc3, 0x19, 0x99, 0x6f, 0x51, 0xfa, 0xa2, 0x26, 0xc2, 0xe4, 0x56, 0x3e, 0xce, 0x23, 0xc9,
|
||||
0xa4, 0x16, 0x0d, 0x71, 0x64, 0x1e, 0xaa, 0x2b, 0x4f, 0xed, 0x00, 0x43, 0x4e, 0xa5, 0x31, 0x8a,
|
||||
0x49, 0x98, 0xda, 0x52, 0x12, 0xd2, 0x91, 0xf7, 0xc2, 0x4c, 0x52, 0x31, 0xde, 0x54, 0x9c, 0x61,
|
||||
0x25, 0x33, 0x9b, 0x64, 0xfc, 0x7d, 0x09, 0x4a, 0x2b, 0x4f, 0x59, 0xe7, 0x98, 0x9b, 0x46, 0xb9,
|
||||
0x59, 0x97, 0x0e, 0x79, 0xb3, 0x7e, 0x91, 0x6c, 0xf6, 0x87, 0xb1, 0x3d, 0x2b, 0xc9, 0xe1, 0x53,
|
||||
0x96, 0x4f, 0x0f, 0x1f, 0x5a, 0xfa, 0xf8, 0x15, 0x43, 0x7e, 0x52, 0x84, 0xe2, 0xe6, 0xd2, 0xc6,
|
||||
0xc9, 0xba, 0x39, 0xd2, 0x75, 0x73, 0x70, 0xea, 0xd1, 0x80, 0xca, 0xa2, 0xd0, 0x51, 0x35, 0xae,
|
||||
0x94, 0x9a, 0x08, 0xa1, 0x12, 0x63, 0x7c, 0x5e, 0x80, 0xda, 0xe6, 0xa0, 0xed, 0xef, 0xf9, 0x01,
|
||||
0xeb, 0x1d, 0x73, 0x6b, 0x5e, 0x96, 0xb1, 0x4d, 0x29, 0xd6, 0x06, 0xb6, 0xa9, 0x8a, 0x88, 0xe6,
|
||||
0x7a, 0xe8, 0x19, 0x95, 0xdb, 0x73, 0xe4, 0x19, 0x43, 0x7f, 0xf8, 0x77, 0x05, 0x98, 0x5a, 0xea,
|
||||
0xda, 0xcc, 0x09, 0x96, 0x6d, 0x5f, 0xde, 0xad, 0x8f, 0xb9, 0x56, 0x0e, 0x97, 0x34, 0xf8, 0x1a,
|
||||
0xd5, 0x76, 0xe3, 0x77, 0x0a, 0x50, 0x5f, 0x1c, 0x04, 0x3b, 0x8b, 0x01, 0x1e, 0x2e, 0xaf, 0xe5,
|
||||
0x31, 0xff, 0xf3, 0x3c, 0x68, 0x94, 0xf9, 0x2c, 0x08, 0x83, 0x95, 0x2d, 0xf7, 0x31, 0x73, 0x5e,
|
||||
0x42, 0x94, 0xa0, 0xde, 0xf6, 0x0b, 0x2f, 0x78, 0xdb, 0x0f, 0x95, 0x5a, 0x7c, 0xce, 0xa8, 0x87,
|
||||
0xc7, 0x91, 0x3c, 0x08, 0x78, 0x45, 0xa6, 0xf1, 0x12, 0xc2, 0xe1, 0xa3, 0x9c, 0xc6, 0xbf, 0xe4,
|
||||
0x61, 0x66, 0xcb, 0xe3, 0x27, 0xba, 0x25, 0x0f, 0xf6, 0x63, 0x6e, 0x97, 0xf1, 0x09, 0x1d, 0x73,
|
||||
0x0b, 0xfd, 0x5b, 0x1e, 0x2e, 0x26, 0x27, 0xf4, 0x2a, 0x78, 0x81, 0x7f, 0xcd, 0xc3, 0xb9, 0x6f,
|
||||
0xdb, 0xc1, 0xce, 0xa0, 0x1d, 0x65, 0x98, 0x5e, 0xbd, 0x19, 0x1d, 0xf3, 0x95, 0xf7, 0xd3, 0x3c,
|
||||
0x9c, 0x5d, 0x5f, 0x5d, 0x5e, 0x7a, 0x55, 0x2c, 0x34, 0x36, 0x9f, 0x57, 0xc0, 0x3e, 0x9b, 0x8b,
|
||||
0xf7, 0xd7, 0x5e, 0x25, 0xfb, 0x24, 0xe6, 0x73, 0xcc, 0xed, 0xf3, 0x7b, 0x15, 0xa8, 0xf3, 0x00,
|
||||
0x57, 0x26, 0x29, 0x5f, 0xeb, 0x2b, 0xff, 0x3c, 0xd4, 0xa5, 0x1a, 0x30, 0xb6, 0x2c, 0xc7, 0x8f,
|
||||
0xff, 0x3c, 0x01, 0x6e, 0x61, 0x8c, 0xa9, 0x12, 0xf1, 0xd0, 0xeb, 0x3b, 0xcc, 0x6b, 0xab, 0xed,
|
||||
0x15, 0xbb, 0xcc, 0x6b, 0x53, 0x84, 0x92, 0xb5, 0xb8, 0x10, 0xb5, 0xb8, 0xb1, 0x8a, 0xef, 0x7e,
|
||||
0x64, 0xc8, 0x8a, 0x0f, 0x99, 0x3c, 0x89, 0x6b, 0x99, 0x7d, 0x5b, 0xbc, 0x18, 0x52, 0x1f, 0x0c,
|
||||
0xa5, 0x39, 0xc9, 0x03, 0x98, 0x0e, 0x61, 0xf1, 0x03, 0x9e, 0x6a, 0x86, 0xb8, 0xac, 0xa7, 0x3b,
|
||||
0xe3, 0xac, 0xe4, 0x43, 0x98, 0x0c, 0x81, 0x1f, 0xdb, 0xf8, 0xbc, 0x80, 0x8b, 0x7a, 0x63, 0x34,
|
||||
0xd4, 0x2f, 0x44, 0xa2, 0x1e, 0xdb, 0x89, 0x6e, 0xb3, 0x04, 0x83, 0x2a, 0x00, 0xe3, 0x4f, 0xc8,
|
||||
0x10, 0x90, 0x2a, 0xb2, 0x25, 0x18, 0xc8, 0x37, 0x50, 0x40, 0xdf, 0x75, 0x7c, 0x86, 0xc9, 0xbe,
|
||||
0x3a, 0xf6, 0x1e, 0x60, 0xc9, 0xcb, 0x93, 0x70, 0xd1, 0x61, 0x92, 0x20, 0x23, 0xeb, 0x00, 0x71,
|
||||
0x52, 0x46, 0xb6, 0xde, 0x3d, 0x77, 0xba, 0x48, 0x11, 0x61, 0xfc, 0x7f, 0x01, 0xce, 0x2c, 0xf6,
|
||||
0xfb, 0x27, 0xaf, 0x74, 0x5e, 0x56, 0x63, 0xc3, 0x1c, 0xc0, 0xc6, 0xa0, 0xdd, 0xb5, 0x3b, 0x4a,
|
||||
0x97, 0x0a, 0xb6, 0x0d, 0xf5, 0x11, 0x2a, 0x1a, 0x55, 0x14, 0x12, 0xe3, 0xf3, 0xa2, 0x6a, 0x01,
|
||||
0x7c, 0x9d, 0x70, 0x62, 0x81, 0xf2, 0xa1, 0x5c, 0xe1, 0x69, 0x55, 0x99, 0xb2, 0x89, 0x4f, 0x56,
|
||||
0x8e, 0xc2, 0x0e, 0xda, 0x0e, 0x47, 0xb5, 0x6c, 0x8b, 0xa6, 0x68, 0x8d, 0xff, 0xc9, 0xc3, 0x74,
|
||||
0x6c, 0x8e, 0x97, 0x71, 0x38, 0xcc, 0x01, 0x88, 0x8c, 0x41, 0x94, 0xd5, 0x3f, 0x25, 0x56, 0x84,
|
||||
0x8f, 0x50, 0xd9, 0x48, 0x16, 0x93, 0x44, 0x29, 0xbe, 0x62, 0x66, 0x8a, 0xef, 0x26, 0x54, 0xa9,
|
||||
0xf9, 0xe4, 0x93, 0x01, 0xf3, 0xf6, 0x64, 0xda, 0x0b, 0xf3, 0x5a, 0x9e, 0xf9, 0xa4, 0xf5, 0x43,
|
||||
0x0e, 0xa4, 0x11, 0x9a, 0x18, 0x51, 0xf3, 0x83, 0x92, 0xc9, 0x11, 0xcd, 0x0f, 0x61, 0xcb, 0x83,
|
||||
0xf1, 0x47, 0x05, 0x98, 0x5a, 0x36, 0x03, 0xb3, 0x6d, 0xfa, 0x71, 0xcb, 0xc0, 0x37, 0xe1, 0x4c,
|
||||
0x08, 0xe3, 0xe6, 0xb1, 0xa3, 0x07, 0xd0, 0xa7, 0x47, 0x43, 0x1d, 0xac, 0x76, 0xcb, 0x17, 0x50,
|
||||
0x9a, 0x26, 0x23, 0xbf, 0x1e, 0x4b, 0x8b, 0x1e, 0xc6, 0x16, 0xe2, 0x4d, 0x60, 0xb5, 0x5b, 0x7d,
|
||||
0x09, 0xa6, 0x63, 0x84, 0xe4, 0x16, 0xd4, 0x43, 0xd8, 0x43, 0xba, 0x2a, 0xe7, 0x8f, 0x1f, 0x6d,
|
||||
0xb5, 0x5b, 0x03, 0xcf, 0xa6, 0x2a, 0x9a, 0xcc, 0xc1, 0x64, 0xf8, 0xaf, 0x92, 0x03, 0xc4, 0xba,
|
||||
0x8a, 0xd5, 0x16, 0xaf, 0xd5, 0x13, 0x04, 0x2a, 0x03, 0xee, 0x90, 0x72, 0x82, 0x01, 0x5f, 0x8f,
|
||||
0x27, 0x08, 0x8c, 0x9f, 0x16, 0x61, 0x26, 0x9e, 0xe0, 0x89, 0x87, 0x7c, 0x39, 0xfb, 0x33, 0xce,
|
||||
0xb6, 0x55, 0x9e, 0xa3, 0xea, 0xd8, 0x80, 0x6a, 0x68, 0x0a, 0x59, 0x26, 0x89, 0xae, 0x8a, 0xe9,
|
||||
0xe5, 0x9b, 0x56, 0x7d, 0x88, 0x37, 0xbe, 0x28, 0x8c, 0xd9, 0x53, 0x6c, 0x94, 0x63, 0x69, 0x4f,
|
||||
0x55, 0x23, 0xa5, 0x17, 0xd3, 0x08, 0x99, 0x87, 0x53, 0xe1, 0xdf, 0xc2, 0xa3, 0x94, 0x95, 0xb6,
|
||||
0xca, 0xb6, 0x74, 0x28, 0x49, 0x12, 0xe3, 0xf7, 0x0b, 0x40, 0x52, 0x5a, 0x3c, 0xb6, 0x8f, 0x63,
|
||||
0x5e, 0x82, 0x0e, 0x8d, 0xbf, 0xce, 0xc3, 0xf4, 0x58, 0xbf, 0x16, 0x79, 0x1f, 0x40, 0x40, 0x94,
|
||||
0xde, 0x2b, 0xec, 0xb9, 0x88, 0x7b, 0xb8, 0x84, 0x8f, 0x52, 0xc8, 0xc8, 0x1c, 0x54, 0xc5, 0x7f,
|
||||
0xd1, 0xaf, 0x46, 0xa4, 0x59, 0x06, 0x03, 0xdb, 0xa2, 0x11, 0x51, 0x3c, 0x0a, 0xfe, 0xce, 0x48,
|
||||
0x31, 0x93, 0x25, 0xd8, 0xeb, 0x47, 0xa3, 0x70, 0x32, 0xe3, 0x8b, 0x3c, 0x4c, 0x46, 0x1f, 0xbc,
|
||||
0x68, 0x1d, 0x95, 0xe9, 0x2a, 0xb2, 0xf5, 0xad, 0xf8, 0xac, 0xd6, 0xb7, 0x94, 0x43, 0x90, 0xbd,
|
||||
0x6e, 0xff, 0x94, 0x87, 0x33, 0x11, 0xed, 0x11, 0xb6, 0x3d, 0x1d, 0x7a, 0x22, 0x3f, 0xb9, 0x00,
|
||||
0xe5, 0x75, 0x87, 0xad, 0x3f, 0x22, 0x77, 0x94, 0x1e, 0x4b, 0xf9, 0xfd, 0xd3, 0xea, 0x77, 0x20,
|
||||
0xa2, 0x99, 0xa3, 0x4a, 0x27, 0xe6, 0x82, 0xda, 0x0b, 0x27, 0xbf, 0x9d, 0xa8, 0x3c, 0x02, 0xd3,
|
||||
0xcc, 0x51, 0xb5, 0x67, 0x6e, 0x41, 0x6d, 0x16, 0x93, 0xdf, 0x9d, 0xe0, 0x12, 0x98, 0x90, 0x4b,
|
||||
0x6a, 0x77, 0x2d, 0xab, 0x37, 0x2b, 0xfd, 0xa2, 0x6c, 0x9c, 0xa2, 0x99, 0xa3, 0xd9, 0x3d, 0x5d,
|
||||
0x89, 0xdf, 0x06, 0x90, 0x47, 0xca, 0x4c, 0x6a, 0x03, 0x23, 0xae, 0x99, 0xa3, 0xc9, 0xdf, 0x11,
|
||||
0xb8, 0x9b, 0x78, 0xd8, 0x2d, 0xcf, 0x91, 0xb3, 0x29, 0x56, 0x8e, 0x6a, 0xe6, 0x68, 0xea, 0x09,
|
||||
0x78, 0xe2, 0x95, 0xb1, 0x3c, 0x49, 0xd2, 0x83, 0x22, 0x4e, 0x19, 0x54, 0xbc, 0x48, 0xfe, 0xcd,
|
||||
0xd4, 0x93, 0x5c, 0x59, 0x52, 0x3f, 0x97, 0x62, 0x16, 0xc8, 0x66, 0x8e, 0xa6, 0x1e, 0xf0, 0xce,
|
||||
0x86, 0x8f, 0x4f, 0x65, 0x57, 0xd2, 0x69, 0x25, 0xd3, 0x61, 0x7f, 0xc6, 0xb5, 0x14, 0x3e, 0x4e,
|
||||
0x5d, 0x50, 0x1f, 0x1d, 0xca, 0xe7, 0x61, 0x24, 0x35, 0xca, 0x8a, 0x63, 0x71, 0xeb, 0x28, 0xfe,
|
||||
0xf7, 0xa3, 0xf4, 0x5b, 0x1f, 0xf9, 0xe8, 0xeb, 0x7c, 0x8a, 0x53, 0x62, 0x9b, 0x39, 0x9a, 0x7e,
|
||||
0x1b, 0x74, 0x37, 0xf1, 0xce, 0x44, 0x46, 0x97, 0x69, 0xad, 0x72, 0x94, 0xa2, 0x55, 0x7c, 0x91,
|
||||
0xf2, 0x51, 0xfa, 0xe1, 0x83, 0x76, 0x2a, 0x73, 0x68, 0x89, 0x55, 0x86, 0x0e, 0x1f, 0x4a, 0xdc,
|
||||
0x4d, 0xb4, 0xd6, 0x6b, 0xa7, 0xb3, 0x87, 0x36, 0x03, 0x53, 0x1d, 0x5a, 0x34, 0xe1, 0x27, 0x9a,
|
||||
0xbc, 0xb5, 0x33, 0x99, 0x06, 0x45, 0x9c, 0x62, 0x50, 0xd1, 0x10, 0x7e, 0x37, 0xd1, 0xcb, 0xa5,
|
||||
0x4d, 0x25, 0x07, 0x55, 0x50, 0x7c, 0x50, 0xb5, 0xeb, 0x6b, 0x41, 0x6d, 0x71, 0xd2, 0xa6, 0x93,
|
||||
0x06, 0x8a, 0x31, 0xdc, 0x40, 0x4a, 0x2b, 0x94, 0x8e, 0xed, 0x13, 0x1a, 0x41, 0xf2, 0x7a, 0xf4,
|
||||
0x85, 0x4b, 0x1b, 0xcd, 0x1c, 0xc5, 0xc6, 0x0a, 0x43, 0x34, 0xe6, 0x68, 0x67, 0x91, 0x62, 0x32,
|
||||
0xa4, 0xe0, 0xb0, 0x66, 0x8e, 0x8a, 0xa6, 0x9d, 0x3b, 0x4a, 0xed, 0x5e, 0x9b, 0x49, 0xba, 0x88,
|
||||
0x08, 0xc1, 0x5d, 0x44, 0x5c, 0xe1, 0xbf, 0x37, 0x5e, 0xdf, 0xd6, 0xce, 0x25, 0xcf, 0xba, 0x34,
|
||||
0xbe, 0x99, 0xa3, 0xe3, 0x35, 0xf1, 0xbb, 0x89, 0x92, 0xaf, 0x76, 0x3e, 0xa9, 0x2e, 0x05, 0xc5,
|
||||
0xd5, 0xa5, 0x16, 0x87, 0xd7, 0x33, 0x1b, 0x29, 0xb5, 0x0b, 0x28, 0xe0, 0x8d, 0x48, 0xc0, 0x38,
|
||||
0x49, 0x33, 0x47, 0x33, 0x5b, 0x30, 0x3f, 0xdd, 0xbf, 0xf0, 0xaa, 0x69, 0x28, 0xf5, 0xaa, 0xb2,
|
||||
0xb9, 0x32, 0xe9, 0x9a, 0x39, 0xba, 0x7f, 0xf1, 0x76, 0x41, 0xad, 0x81, 0x6a, 0x17, 0x93, 0xf6,
|
||||
0x8d, 0x31, 0xdc, 0xbe, 0x4a, 0xad, 0x74, 0x41, 0x2d, 0x39, 0x6a, 0x97, 0xc6, 0xb9, 0x62, 0xa7,
|
||||
0xaa, 0x94, 0x26, 0x69, 0x76, 0x85, 0x4f, 0x7b, 0x03, 0xf9, 0x2f, 0x87, 0xfc, 0x59, 0x34, 0xcd,
|
||||
0x1c, 0xcd, 0xae, 0x0e, 0xd2, 0xec, 0x22, 0x9b, 0x76, 0xf9, 0x20, 0x99, 0xd1, 0xd7, 0x65, 0x17,
|
||||
0xe8, 0xcc, 0x03, 0xea, 0x5c, 0xda, 0x9b, 0xc9, 0x44, 0xd4, 0xbe, 0x84, 0xcd, 0x1c, 0x3d, 0xa0,
|
||||
0x5a, 0xf6, 0x70, 0x9f, 0xa2, 0x93, 0x76, 0x25, 0xd9, 0xbb, 0x94, 0x49, 0xd4, 0xcc, 0xd1, 0x7d,
|
||||
0x4a, 0x56, 0x0f, 0xf7, 0xa9, 0xfc, 0x68, 0xfa, 0x81, 0x62, 0x23, 0x7d, 0xec, 0x53, 0x37, 0x5a,
|
||||
0xcf, 0x2c, 0xbf, 0x68, 0x57, 0x93, 0xab, 0x3a, 0x83, 0x84, 0xaf, 0xea, 0xac, 0xc2, 0xcd, 0x7a,
|
||||
0x66, 0xfd, 0x43, 0xbb, 0x76, 0x80, 0xc0, 0xe8, 0x1b, 0x33, 0x2b, 0x27, 0xeb, 0x99, 0x05, 0x08,
|
||||
0xcd, 0x48, 0x0a, 0xcc, 0x20, 0xe1, 0x02, 0xb3, 0x4a, 0x17, 0xeb, 0x99, 0x15, 0x00, 0xed, 0xfa,
|
||||
0x01, 0x02, 0xe3, 0x2f, 0xcc, 0xaa, 0x1d, 0xdc, 0x4d, 0xa4, 0xe0, 0xb5, 0xb7, 0x92, 0x2e, 0x45,
|
||||
0x41, 0x71, 0x97, 0xa2, 0x26, 0xeb, 0x97, 0xc6, 0xb2, 0x96, 0xda, 0xdb, 0xc9, 0x00, 0x20, 0x85,
|
||||
0x6e, 0xe6, 0xe8, 0x58, 0x9e, 0x73, 0x69, 0x2c, 0xf1, 0xa6, 0xdd, 0xd8, 0x4f, 0x08, 0xa2, 0x93,
|
||||
0x42, 0x44, 0xaa, 0x6e, 0x35, 0x23, 0x5d, 0xa4, 0xbd, 0x93, 0xbc, 0x09, 0x8e, 0x11, 0x34, 0x73,
|
||||
0x34, 0x23, 0xc9, 0x44, 0xb3, 0xb3, 0x0d, 0xda, 0x6c, 0x72, 0xdb, 0x66, 0xd1, 0xf0, 0x6d, 0x9b,
|
||||
0x99, 0xa9, 0x58, 0xcb, 0x8a, 0xd5, 0xb4, 0x9b, 0xc9, 0x3b, 0xdb, 0x38, 0x05, 0xbf, 0xb3, 0x65,
|
||||
0xc4, 0x78, 0x34, 0x3b, 0x7e, 0xd6, 0x7e, 0xe5, 0xc0, 0x2f, 0x44, 0x9a, 0x8c, 0x2f, 0x14, 0xb1,
|
||||
0x77, 0x7c, 0xad, 0x7a, 0xd8, 0xef, 0xba, 0xa6, 0xa5, 0xbd, 0x9b, 0x79, 0xad, 0x12, 0x48, 0xe5,
|
||||
0x5a, 0x25, 0x00, 0xfc, 0x02, 0xa0, 0xc6, 0x32, 0xda, 0xad, 0xe4, 0x05, 0x40, 0xc5, 0xf1, 0x0b,
|
||||
0x40, 0x22, 0xee, 0x59, 0x1a, 0x8b, 0x20, 0xb4, 0xf7, 0x92, 0x0b, 0x20, 0x85, 0xe6, 0x0b, 0x20,
|
||||
0x05, 0x6a, 0x4c, 0x40, 0x79, 0x85, 0x13, 0x1b, 0x7f, 0x9a, 0x87, 0xc9, 0xcd, 0xc0, 0x63, 0x66,
|
||||
0x4f, 0xa6, 0x2c, 0x2e, 0x41, 0x55, 0x7c, 0x64, 0xf8, 0x53, 0x88, 0x34, 0xfa, 0x9f, 0xdc, 0x80,
|
||||
0xd3, 0x6b, 0xa6, 0x1f, 0x20, 0xa7, 0xf2, 0x33, 0x35, 0x34, 0x05, 0x25, 0x6b, 0x82, 0x4e, 0xf0,
|
||||
0xe1, 0xcf, 0x05, 0x14, 0x9f, 0xf9, 0x36, 0xa7, 0xca, 0xc3, 0x0c, 0x7c, 0x90, 0x93, 0xe2, 0x35,
|
||||
0x46, 0x79, 0x18, 0x53, 0xdf, 0x8b, 0x47, 0x4c, 0xeb, 0x63, 0x3f, 0xff, 0x28, 0x03, 0x90, 0xaf,
|
||||
0x19, 0x85, 0x8f, 0xfd, 0x78, 0xe4, 0x75, 0x28, 0x3e, 0x5c, 0x5d, 0x56, 0x9f, 0xff, 0x24, 0x7f,
|
||||
0x11, 0x93, 0x63, 0xc9, 0x3b, 0xd1, 0xed, 0xf8, 0x21, 0x5d, 0x93, 0xf9, 0x0a, 0x7c, 0xde, 0x3f,
|
||||
0xf0, 0xba, 0x54, 0x41, 0x35, 0xa6, 0xbe, 0xfc, 0xaf, 0x2b, 0xb9, 0x2f, 0xbf, 0xba, 0x92, 0xff,
|
||||
0xd9, 0x57, 0x57, 0xf2, 0xff, 0xf9, 0xd5, 0x95, 0x7c, 0xbb, 0x82, 0xca, 0x7a, 0xff, 0x17, 0x01,
|
||||
0x00, 0x00, 0xff, 0xff, 0xf7, 0xd0, 0x29, 0x5d, 0x2e, 0x54, 0x00, 0x00,
|
||||
0x54, 0x2c, 0x8b, 0x11, 0xcd, 0xb5, 0x36, 0x9b, 0x0f, 0x9b, 0x43, 0x52, 0x3b, 0x8c, 0x29, 0x91,
|
||||
0x2e, 0x52, 0x9b, 0xbd, 0xac, 0x07, 0x3d, 0xd3, 0x25, 0xb2, 0x57, 0x33, 0xdd, 0xb3, 0xdd, 0x3d,
|
||||
0x94, 0xe8, 0x53, 0x3e, 0x2e, 0x7b, 0x70, 0x80, 0x60, 0x73, 0x08, 0x82, 0x1c, 0x12, 0x20, 0xc8,
|
||||
0x21, 0x41, 0x90, 0x04, 0x39, 0x04, 0xb9, 0x3b, 0x1b, 0x18, 0x08, 0x36, 0x59, 0x6c, 0xce, 0x99,
|
||||
0x24, 0x06, 0x72, 0x19, 0x20, 0x7f, 0x20, 0x08, 0x90, 0xa0, 0x5e, 0x55, 0x77, 0x57, 0xf7, 0x34,
|
||||
0x29, 0x4b, 0xd4, 0x82, 0xa0, 0xc4, 0x1b, 0xf9, 0xbe, 0xba, 0xea, 0xbd, 0xaa, 0x57, 0xf5, 0x3e,
|
||||
0x6a, 0x60, 0x92, 0xed, 0x32, 0x27, 0xf0, 0x6f, 0xf7, 0x3d, 0x37, 0x70, 0x49, 0x45, 0xfc, 0x77,
|
||||
0x69, 0x66, 0xdb, 0xdd, 0x76, 0x11, 0x34, 0xc7, 0xff, 0x12, 0xd8, 0x4b, 0xfa, 0xb6, 0xeb, 0x6e,
|
||||
0x77, 0xd9, 0x1c, 0xfe, 0xd7, 0x1e, 0x3c, 0x9a, 0x0b, 0xec, 0x1e, 0xf3, 0x03, 0xb3, 0xd7, 0x97,
|
||||
0x04, 0x97, 0xd3, 0x04, 0x7e, 0xe0, 0x0d, 0x3a, 0x81, 0xc0, 0x1a, 0x3f, 0x2c, 0x40, 0xf5, 0x3e,
|
||||
0x0b, 0x4c, 0xcb, 0x0c, 0x4c, 0x72, 0x19, 0xca, 0xab, 0x8e, 0xc5, 0x9e, 0x6a, 0xf9, 0xab, 0xf9,
|
||||
0xd9, 0x62, 0xa3, 0x32, 0x1a, 0xea, 0x05, 0x66, 0x53, 0x01, 0x24, 0x6f, 0x42, 0x69, 0x6b, 0xaf,
|
||||
0xcf, 0xb4, 0xc2, 0xd5, 0xfc, 0x6c, 0xad, 0x51, 0x1b, 0x0d, 0xf5, 0x32, 0x8e, 0x8c, 0x22, 0x98,
|
||||
0x5c, 0x83, 0xc2, 0xea, 0xb2, 0x56, 0x44, 0xe4, 0xf4, 0x68, 0xa8, 0x9f, 0x1a, 0xd8, 0xd6, 0x2d,
|
||||
0xb7, 0x67, 0x07, 0xac, 0xd7, 0x0f, 0xf6, 0x68, 0x61, 0x75, 0x99, 0xdc, 0x80, 0xd2, 0x92, 0x6b,
|
||||
0x31, 0xad, 0x84, 0x44, 0x64, 0x34, 0xd4, 0x4f, 0x77, 0x5c, 0x8b, 0x29, 0x54, 0x88, 0x27, 0x1f,
|
||||
0x41, 0x69, 0xcb, 0xee, 0x31, 0xad, 0x7c, 0x35, 0x3f, 0x5b, 0x9f, 0xbf, 0x74, 0x5b, 0xcc, 0xe0,
|
||||
0x76, 0x38, 0x83, 0xdb, 0x5b, 0xe1, 0x14, 0x1b, 0x53, 0x5f, 0x0e, 0xf5, 0xdc, 0x68, 0xa8, 0x97,
|
||||
0xf8, 0xac, 0x7f, 0xef, 0xdf, 0xf5, 0x3c, 0x45, 0x4e, 0x32, 0x0f, 0xf5, 0xa5, 0xee, 0xc0, 0x0f,
|
||||
0x98, 0xf7, 0xc0, 0xec, 0x31, 0xad, 0x82, 0x1f, 0x9c, 0x1a, 0x0d, 0xf5, 0xc9, 0x8e, 0x00, 0xb7,
|
||||
0x1c, 0xb3, 0xc7, 0xa8, 0x4a, 0x64, 0x7c, 0x1f, 0xce, 0x6c, 0x32, 0xdf, 0xb7, 0x5d, 0x27, 0x52,
|
||||
0xc8, 0xdb, 0x50, 0x93, 0xa0, 0xd5, 0x65, 0x54, 0x4a, 0xad, 0x31, 0x31, 0x1a, 0xea, 0x45, 0xdf,
|
||||
0xb6, 0x68, 0x8c, 0x21, 0xbf, 0x08, 0x13, 0xbf, 0x61, 0x07, 0x3b, 0xf7, 0xef, 0x2d, 0x4a, 0xe5,
|
||||
0x9c, 0x1f, 0x0d, 0x75, 0xf2, 0xc4, 0x0e, 0x76, 0x5a, 0xbd, 0x47, 0xa6, 0x32, 0xbd, 0x90, 0xcc,
|
||||
0xf8, 0x83, 0x3c, 0x4c, 0x3e, 0xf4, 0x99, 0xa7, 0xa8, 0xbe, 0xc4, 0xff, 0x97, 0x1f, 0xa9, 0xf2,
|
||||
0x29, 0x0d, 0x7c, 0xe6, 0x51, 0x84, 0x92, 0x9b, 0x50, 0x5e, 0x73, 0xb7, 0x6d, 0x47, 0x8a, 0x3f,
|
||||
0x3b, 0x1a, 0xea, 0x67, 0xba, 0x1c, 0xa0, 0xc8, 0x16, 0x14, 0xe4, 0xd7, 0x60, 0x72, 0xb5, 0xd7,
|
||||
0x67, 0x9e, 0xef, 0x3a, 0x66, 0xe0, 0x7a, 0xd2, 0x20, 0x97, 0x46, 0x43, 0xfd, 0xbc, 0xad, 0xc0,
|
||||
0x15, 0xc6, 0x04, 0xbd, 0xf1, 0x37, 0x45, 0x38, 0xbd, 0xc9, 0xbc, 0x5d, 0x65, 0x6c, 0x8b, 0x5c,
|
||||
0x31, 0x1c, 0xc2, 0xd5, 0xe4, 0xf7, 0xcd, 0x0e, 0x93, 0xc3, 0xbc, 0x30, 0x1a, 0xea, 0x67, 0x9d,
|
||||
0x10, 0xa8, 0x88, 0x4c, 0xd3, 0x93, 0x9b, 0x50, 0x15, 0xa0, 0xd5, 0x65, 0x39, 0x87, 0x53, 0xa3,
|
||||
0xa1, 0x5e, 0xf3, 0x11, 0xd6, 0xb2, 0x2d, 0x1a, 0xa1, 0xc9, 0x4a, 0xf8, 0xfd, 0xa6, 0xeb, 0x07,
|
||||
0x5c, 0xb8, 0x9c, 0xc2, 0x9b, 0xa3, 0xa1, 0x7e, 0x51, 0x32, 0xec, 0x48, 0x94, 0xf2, 0xc9, 0x14,
|
||||
0x13, 0xf9, 0x25, 0x00, 0x01, 0x59, 0xb4, 0x2c, 0x4f, 0xae, 0xb8, 0x8b, 0xa3, 0xa1, 0x7e, 0x4e,
|
||||
0x8a, 0x30, 0x2d, 0x4b, 0x55, 0x82, 0x42, 0x4c, 0x7a, 0x30, 0x29, 0xfe, 0x5b, 0x33, 0xdb, 0xac,
|
||||
0xeb, 0x6b, 0xe5, 0xab, 0xc5, 0xd9, 0xfa, 0xfc, 0xec, 0x6d, 0xb9, 0x2b, 0x93, 0xda, 0xb9, 0xad,
|
||||
0x92, 0xae, 0x38, 0x81, 0xb7, 0xd7, 0xd0, 0xe5, 0xa2, 0xbc, 0x20, 0x3f, 0xd5, 0x45, 0x9c, 0xaa,
|
||||
0x71, 0x95, 0xe7, 0xd2, 0x87, 0x30, 0x3d, 0x26, 0x83, 0x4c, 0x41, 0xf1, 0x31, 0xdb, 0x13, 0x7a,
|
||||
0xa6, 0xfc, 0x4f, 0x32, 0x03, 0xe5, 0x5d, 0xb3, 0x3b, 0x90, 0xfb, 0x8f, 0x8a, 0x7f, 0xbe, 0x55,
|
||||
0xf8, 0x66, 0xde, 0xf8, 0xfb, 0x3c, 0x90, 0x25, 0xd7, 0x71, 0x58, 0x27, 0x50, 0x17, 0xef, 0x07,
|
||||
0x50, 0x5b, 0x73, 0x3b, 0x66, 0x17, 0x15, 0x20, 0x0c, 0xa6, 0x8d, 0x86, 0xfa, 0x0c, 0x9f, 0xf9,
|
||||
0xed, 0x2e, 0xc7, 0x28, 0x43, 0x8a, 0x49, 0xb9, 0xe6, 0x28, 0xeb, 0xb9, 0x01, 0x43, 0xc6, 0x42,
|
||||
0xac, 0x39, 0x64, 0xf4, 0x10, 0xa5, 0x6a, 0x2e, 0x26, 0x26, 0x73, 0x50, 0xdd, 0xe0, 0x9b, 0xb4,
|
||||
0xe3, 0x76, 0xa5, 0xd5, 0x70, 0xa9, 0xe2, 0xc6, 0x55, 0x58, 0x22, 0x22, 0xe3, 0xb7, 0x0b, 0x70,
|
||||
0xf1, 0xe3, 0x41, 0x9b, 0x79, 0x0e, 0x0b, 0x98, 0x2f, 0x77, 0x63, 0x34, 0x83, 0x07, 0x30, 0x3d,
|
||||
0x86, 0x94, 0x33, 0xb9, 0x3a, 0x1a, 0xea, 0x97, 0x1f, 0x47, 0xc8, 0x96, 0xdc, 0xd6, 0xca, 0x47,
|
||||
0xc6, 0x59, 0x49, 0x13, 0xce, 0xc4, 0x40, 0xbe, 0xb1, 0x7c, 0xad, 0x70, 0xb5, 0x38, 0x5b, 0x6b,
|
||||
0x5c, 0x19, 0x0d, 0xf5, 0x4b, 0x8a, 0x34, 0xbe, 0xf5, 0x54, 0x83, 0xa5, 0xd9, 0xc8, 0xc7, 0x30,
|
||||
0x15, 0x83, 0xbe, 0xed, 0xb9, 0x83, 0xbe, 0xaf, 0x15, 0x51, 0x94, 0x3e, 0x1a, 0xea, 0x6f, 0x28,
|
||||
0xa2, 0xb6, 0x11, 0xa9, 0xc8, 0x1a, 0x63, 0x34, 0xfe, 0xab, 0x08, 0xe7, 0x62, 0xe0, 0x86, 0x6b,
|
||||
0x45, 0x0a, 0x58, 0x57, 0x15, 0xb0, 0xe1, 0x5a, 0xe8, 0xcc, 0x84, 0x02, 0xae, 0x8d, 0x86, 0xfa,
|
||||
0x9b, 0xca, 0x77, 0xfa, 0xae, 0xd5, 0x4a, 0x6d, 0x89, 0x71, 0x5e, 0xf2, 0x29, 0x9c, 0x1f, 0x03,
|
||||
0x8a, 0x1d, 0x2d, 0xec, 0x7c, 0x63, 0x34, 0xd4, 0x8d, 0x0c, 0xa9, 0xe9, 0x0d, 0xbe, 0x8f, 0x14,
|
||||
0x62, 0xc2, 0x05, 0x45, 0xed, 0xae, 0x13, 0x98, 0xb6, 0x23, 0x7d, 0xb0, 0x58, 0x0f, 0xef, 0x8c,
|
||||
0x86, 0xfa, 0x75, 0xd5, 0x6e, 0x21, 0x4d, 0x7a, 0xf0, 0xfb, 0xc9, 0x21, 0x16, 0x68, 0x19, 0xa8,
|
||||
0xd5, 0x9e, 0xb9, 0x1d, 0x1e, 0x2c, 0xb3, 0xa3, 0xa1, 0xfe, 0x56, 0xe6, 0x37, 0x6c, 0x4e, 0xa5,
|
||||
0x7c, 0x64, 0x5f, 0x49, 0x84, 0x02, 0x89, 0x71, 0x0f, 0x5c, 0x8b, 0xe1, 0x1c, 0xca, 0x28, 0xdf,
|
||||
0x18, 0x0d, 0xf5, 0x2b, 0x8a, 0x7c, 0xc7, 0xb5, 0x58, 0x7a, 0xf8, 0x19, 0xdc, 0xc6, 0xff, 0x96,
|
||||
0xb8, 0x63, 0xc1, 0x43, 0x63, 0x33, 0x30, 0xbd, 0x80, 0x7c, 0x2b, 0x3e, 0x7b, 0xd1, 0xaa, 0xf5,
|
||||
0xf9, 0xa9, 0xd0, 0xc9, 0x84, 0xf0, 0xc6, 0x24, 0x77, 0x26, 0x3f, 0x1d, 0xea, 0xf9, 0xd1, 0x50,
|
||||
0xcf, 0xd1, 0xaa, 0xb2, 0xbb, 0xc5, 0x81, 0x51, 0x40, 0xbe, 0x99, 0x90, 0x4f, 0x3d, 0x54, 0x52,
|
||||
0xbc, 0xe2, 0x28, 0xf9, 0x10, 0x26, 0xe4, 0x18, 0xd0, 0x22, 0xf5, 0xf9, 0x0b, 0xb1, 0x5f, 0x4b,
|
||||
0x1c, 0x7e, 0x29, 0xee, 0x90, 0x8b, 0xfc, 0x0a, 0x54, 0x84, 0xbb, 0x42, 0x6d, 0xd7, 0xe7, 0xcf,
|
||||
0x67, 0xfb, 0xc5, 0x14, 0xbb, 0xe4, 0x21, 0x4d, 0x80, 0xd8, 0x55, 0x45, 0x07, 0xbc, 0x94, 0x30,
|
||||
0xee, 0xc4, 0x52, 0x52, 0x14, 0x5e, 0xf2, 0x01, 0x4c, 0x6e, 0x31, 0xaf, 0x67, 0x3b, 0x66, 0x77,
|
||||
0xd3, 0xfe, 0x2c, 0x3c, 0xe3, 0xf1, 0x52, 0xe1, 0xdb, 0x9f, 0xa9, 0xb6, 0x48, 0xd0, 0x91, 0xef,
|
||||
0x65, 0x39, 0x95, 0x09, 0x1c, 0xc8, 0xb5, 0x70, 0x20, 0xfb, 0xba, 0xa4, 0xd4, 0x78, 0x32, 0x7c,
|
||||
0xcc, 0x27, 0x70, 0x2a, 0xb1, 0x37, 0xb4, 0x2a, 0x8a, 0x7e, 0x73, 0x5c, 0xb4, 0xb2, 0xd1, 0x53,
|
||||
0x62, 0x93, 0x12, 0xf8, 0x89, 0xb8, 0xea, 0xd8, 0x81, 0x6d, 0x76, 0x97, 0xdc, 0x5e, 0xcf, 0x74,
|
||||
0x2c, 0xad, 0x86, 0xae, 0x06, 0x4f, 0x44, 0x5b, 0x60, 0x5a, 0x1d, 0x81, 0x52, 0x4f, 0xc4, 0x24,
|
||||
0x93, 0xf1, 0xe7, 0x45, 0xa8, 0x4b, 0x23, 0xfe, 0xba, 0x6b, 0x3b, 0x27, 0xab, 0xef, 0x30, 0xab,
|
||||
0x2f, 0x73, 0x15, 0x55, 0x5e, 0xd6, 0x2a, 0x32, 0x3e, 0x2f, 0x44, 0xae, 0x62, 0xc3, 0xb3, 0x9d,
|
||||
0xc3, 0xb9, 0x8a, 0x1b, 0x00, 0x4b, 0x3b, 0x03, 0xe7, 0xb1, 0xb8, 0xdb, 0x17, 0xe2, 0xbb, 0x7d,
|
||||
0xc7, 0xa6, 0x0a, 0x86, 0x5f, 0xf0, 0x97, 0xb9, 0x7c, 0x6e, 0x99, 0xc9, 0x46, 0xed, 0x4b, 0x21,
|
||||
0x29, 0xff, 0x1e, 0x45, 0x30, 0xd1, 0xa1, 0xdc, 0xd8, 0x0b, 0x98, 0x8f, 0x9a, 0x2f, 0x8a, 0x00,
|
||||
0xa0, 0xcd, 0x01, 0x54, 0xc0, 0xc9, 0x02, 0x4c, 0x2f, 0xb3, 0xae, 0xb9, 0x77, 0xdf, 0xee, 0x76,
|
||||
0x6d, 0x9f, 0x75, 0x5c, 0xc7, 0xf2, 0x51, 0xc9, 0xf2, 0x73, 0x3d, 0x9f, 0x8e, 0x13, 0x10, 0x03,
|
||||
0x2a, 0xeb, 0x8f, 0x1e, 0xf9, 0x2c, 0x40, 0xf5, 0x15, 0x1b, 0x30, 0x1a, 0xea, 0x15, 0x17, 0x21,
|
||||
0x54, 0x62, 0x8c, 0x9f, 0x15, 0xe0, 0x94, 0x54, 0x07, 0x65, 0xdf, 0x67, 0x9d, 0xa3, 0x71, 0x9d,
|
||||
0xf1, 0xda, 0x2b, 0x1e, 0x7a, 0xed, 0x95, 0x0e, 0xb1, 0xf6, 0x0c, 0xa8, 0x50, 0x66, 0xfa, 0x72,
|
||||
0x05, 0xd7, 0x84, 0xc6, 0x3c, 0x84, 0x50, 0x89, 0x21, 0xd7, 0x60, 0xe2, 0xbe, 0xf9, 0xd4, 0xee,
|
||||
0x0d, 0x7a, 0x52, 0xad, 0x18, 0xb7, 0xf4, 0xcc, 0xa7, 0x34, 0x84, 0x1b, 0x7f, 0x5d, 0xe2, 0x72,
|
||||
0xb8, 0xaf, 0x3c, 0x9e, 0xae, 0xe0, 0xe5, 0x29, 0x34, 0x36, 0x6c, 0xf9, 0x05, 0x0c, 0xfb, 0xda,
|
||||
0x1c, 0x44, 0xc6, 0x5f, 0x4c, 0xf0, 0xa0, 0x0a, 0xb5, 0xbf, 0xe2, 0x58, 0x27, 0xab, 0xe6, 0x30,
|
||||
0xab, 0x66, 0x19, 0xa6, 0x57, 0x9c, 0x1d, 0xd3, 0xe9, 0x30, 0x8b, 0xb2, 0x8e, 0xeb, 0x59, 0xb6,
|
||||
0xb3, 0x8d, 0x4b, 0xa7, 0x2a, 0xb2, 0x07, 0x4c, 0x22, 0x5b, 0x5e, 0x88, 0xa5, 0xe3, 0x0c, 0xe4,
|
||||
0x0e, 0xd4, 0x57, 0x9d, 0x80, 0x79, 0x66, 0x27, 0xb0, 0x77, 0x19, 0xae, 0x9e, 0x6a, 0xe3, 0xcc,
|
||||
0x68, 0xa8, 0xd7, 0xed, 0x18, 0x4c, 0x55, 0x1a, 0xb2, 0x00, 0x93, 0x1b, 0xa6, 0x17, 0xd8, 0x1d,
|
||||
0xbb, 0x6f, 0x3a, 0x81, 0xaf, 0x55, 0xf1, 0x2e, 0x81, 0xb9, 0x91, 0xbe, 0x02, 0xa7, 0x09, 0x2a,
|
||||
0xf2, 0x3d, 0xa8, 0xe1, 0x9d, 0x15, 0xf3, 0x32, 0xb5, 0x67, 0xe6, 0x65, 0xae, 0xc7, 0x21, 0x30,
|
||||
0xaa, 0xbd, 0xe5, 0x73, 0xe6, 0x78, 0x2b, 0x60, 0xaa, 0x26, 0x96, 0x48, 0xbe, 0x0b, 0x13, 0x2b,
|
||||
0x8e, 0x85, 0xc2, 0xe1, 0x99, 0xc2, 0x0d, 0x29, 0xfc, 0x7c, 0x2c, 0xdc, 0xed, 0xa7, 0x64, 0x87,
|
||||
0xe2, 0xb2, 0x77, 0x59, 0xfd, 0xe7, 0xb7, 0xcb, 0x26, 0x7f, 0x0e, 0xd7, 0xbd, 0x53, 0x2f, 0x72,
|
||||
0xdd, 0xfb, 0x0c, 0xea, 0x8d, 0x8d, 0x7b, 0xd1, 0x86, 0xbb, 0x08, 0xc5, 0x0d, 0x99, 0xc4, 0x2a,
|
||||
0x89, 0xc3, 0xa0, 0x6f, 0x5b, 0x94, 0xc3, 0xc8, 0x4d, 0xa8, 0x2e, 0x61, 0x98, 0x2a, 0x93, 0x33,
|
||||
0x25, 0x91, 0x9c, 0xe9, 0x20, 0x0c, 0x93, 0x33, 0x21, 0x9a, 0xbc, 0x0d, 0x13, 0x1b, 0x9e, 0xbb,
|
||||
0xed, 0x99, 0x3d, 0x19, 0xcf, 0xd5, 0x47, 0x43, 0x7d, 0xa2, 0x2f, 0x40, 0x34, 0xc4, 0x19, 0xbf,
|
||||
0x9f, 0x87, 0xca, 0x66, 0x60, 0x06, 0x03, 0x9f, 0x73, 0x6c, 0x0e, 0x3a, 0x1d, 0xe6, 0xfb, 0xf8,
|
||||
0xed, 0xaa, 0xe0, 0xf0, 0x05, 0x88, 0x86, 0x38, 0x72, 0x13, 0xca, 0x2b, 0x9e, 0xe7, 0x7a, 0x6a,
|
||||
0x86, 0x8b, 0x71, 0x80, 0x9a, 0xe1, 0x42, 0x0a, 0x72, 0x17, 0xea, 0xc2, 0x4d, 0xf8, 0x3e, 0x8f,
|
||||
0xf9, 0xc4, 0x38, 0xce, 0x8d, 0x86, 0xfa, 0x74, 0x4f, 0x80, 0x14, 0x16, 0x95, 0xd2, 0xf8, 0x02,
|
||||
0x53, 0x5b, 0xb8, 0x64, 0xa4, 0x92, 0x5e, 0xc7, 0x3b, 0xf0, 0xfb, 0x50, 0x6c, 0x6c, 0xdc, 0x93,
|
||||
0x3e, 0xeb, 0x6c, 0xc8, 0xaa, 0x2c, 0x95, 0x14, 0x1f, 0xa7, 0x26, 0x97, 0xa1, 0xb4, 0xc1, 0x97,
|
||||
0x4f, 0x05, 0x97, 0x07, 0xa6, 0x27, 0xfb, 0x7c, 0xfd, 0x20, 0x14, 0xb1, 0x66, 0xb0, 0x83, 0xee,
|
||||
0x47, 0x26, 0x2f, 0xfb, 0x66, 0xb0, 0x43, 0x11, 0xca, 0xb1, 0x8b, 0xde, 0xf6, 0xae, 0x74, 0x34,
|
||||
0x88, 0x35, 0xbd, 0xed, 0x5d, 0x8a, 0x50, 0x32, 0x07, 0x40, 0x59, 0x30, 0xf0, 0x1c, 0xcc, 0x0c,
|
||||
0x73, 0xcf, 0x52, 0x16, 0x0e, 0xcc, 0x43, 0x68, 0xab, 0xe3, 0x5a, 0x8c, 0x2a, 0x24, 0xc6, 0x9f,
|
||||
0xc5, 0x61, 0xcc, 0xb2, 0xed, 0x3f, 0x3e, 0x31, 0xe1, 0x73, 0x98, 0x90, 0x1b, 0xa9, 0x92, 0x69,
|
||||
0x24, 0x1d, 0xca, 0xf7, 0xba, 0xe6, 0xb6, 0x8f, 0x36, 0x2c, 0x8b, 0xcb, 0xfd, 0x23, 0x0e, 0xa0,
|
||||
0x02, 0x9e, 0xb2, 0x53, 0xf5, 0xd9, 0x76, 0xfa, 0xb7, 0x78, 0xb7, 0x3d, 0x60, 0xc1, 0x13, 0xd7,
|
||||
0x3b, 0x31, 0xd5, 0xd7, 0x35, 0xd5, 0x0d, 0x98, 0xd8, 0xf4, 0x3a, 0x98, 0x7e, 0x15, 0xd6, 0x9a,
|
||||
0x1c, 0x0d, 0xf5, 0xaa, 0xef, 0x75, 0x30, 0x6b, 0x4d, 0x43, 0x24, 0xa7, 0x5b, 0xf6, 0x03, 0xa4,
|
||||
0x9b, 0x88, 0xe9, 0x2c, 0x3f, 0x90, 0x74, 0x12, 0x29, 0xe9, 0x36, 0x5c, 0x2f, 0x90, 0x86, 0x8b,
|
||||
0xe8, 0xfa, 0xae, 0x17, 0xd0, 0x10, 0x49, 0xde, 0x05, 0xd8, 0x5a, 0xda, 0xf8, 0x0e, 0xf3, 0x50,
|
||||
0x5d, 0x62, 0x2f, 0xa2, 0xbb, 0xde, 0x15, 0x20, 0xaa, 0xa0, 0x8d, 0xbf, 0x54, 0xf6, 0x21, 0x37,
|
||||
0xd0, 0x49, 0x3a, 0xe1, 0x10, 0x77, 0xc9, 0x79, 0x98, 0xc2, 0x18, 0x7a, 0xcb, 0x33, 0x1d, 0xbf,
|
||||
0x67, 0x07, 0x01, 0xb3, 0xa4, 0xaf, 0xc5, 0xc8, 0x39, 0x78, 0x4a, 0xc7, 0xf0, 0xe4, 0x16, 0x9c,
|
||||
0x42, 0x18, 0x65, 0x1d, 0x66, 0xef, 0x32, 0x0b, 0xd7, 0x80, 0x64, 0xf0, 0x9e, 0xd2, 0x24, 0xd2,
|
||||
0xf8, 0xa7, 0x38, 0xa3, 0xb0, 0xc6, 0xcc, 0x5d, 0x76, 0x62, 0xaf, 0x43, 0xd8, 0xcb, 0xf8, 0xd3,
|
||||
0x22, 0xd4, 0xf8, 0x8c, 0x44, 0xcd, 0xed, 0x28, 0x54, 0xb9, 0x10, 0xde, 0xb0, 0xa4, 0x26, 0x4f,
|
||||
0x47, 0x9a, 0x40, 0xe8, 0x98, 0x06, 0xc4, 0x6d, 0xec, 0x16, 0x54, 0xee, 0xb3, 0x60, 0xc7, 0xb5,
|
||||
0x64, 0xaa, 0x7c, 0x66, 0x34, 0xd4, 0xa7, 0x7a, 0x08, 0x51, 0x6e, 0x4d, 0x92, 0x86, 0x3c, 0x06,
|
||||
0xb2, 0x6a, 0x31, 0x27, 0xb0, 0x83, 0xbd, 0xc5, 0x20, 0xf0, 0xec, 0xf6, 0x20, 0x60, 0xbe, 0xd4,
|
||||
0xdb, 0x85, 0xb1, 0x0b, 0xfa, 0x26, 0xd6, 0x95, 0x31, 0x3b, 0x3e, 0x63, 0x46, 0xe4, 0xb1, 0xd8,
|
||||
0xff, 0x19, 0xea, 0x15, 0x41, 0x43, 0x33, 0xc4, 0x92, 0x4f, 0xa0, 0x76, 0xff, 0xde, 0xe2, 0x32,
|
||||
0xdb, 0xb5, 0x3b, 0x4c, 0x66, 0xd2, 0x2e, 0x46, 0x5a, 0x0c, 0x11, 0x91, 0x4a, 0xb0, 0x92, 0xd5,
|
||||
0x7b, 0x64, 0xb6, 0x2c, 0x84, 0xab, 0x95, 0xac, 0x88, 0xd8, 0xf8, 0x2a, 0x0f, 0x53, 0x94, 0xf9,
|
||||
0xee, 0xc0, 0x8b, 0x39, 0xc9, 0x0d, 0x28, 0x29, 0x65, 0x14, 0x0c, 0xd3, 0x53, 0xb9, 0x7b, 0xc4,
|
||||
0x93, 0x55, 0x98, 0x58, 0x79, 0xda, 0xb7, 0x3d, 0xe6, 0x4b, 0xdb, 0x1c, 0x14, 0x92, 0x9c, 0x95,
|
||||
0x21, 0xc9, 0x04, 0x13, 0x2c, 0x32, 0x06, 0x11, 0xff, 0x90, 0x0f, 0xa0, 0xf6, 0xb0, 0x6f, 0x99,
|
||||
0x01, 0xb3, 0x1a, 0x7b, 0xf2, 0xbe, 0x8a, 0xe3, 0x1f, 0x08, 0x60, 0xab, 0xbd, 0xa7, 0x8e, 0x3f,
|
||||
0x22, 0x25, 0xd7, 0xa1, 0xb8, 0xb5, 0xb5, 0x26, 0x4d, 0x85, 0x35, 0xf5, 0x20, 0x50, 0x8b, 0x76,
|
||||
0x1c, 0x6b, 0xfc, 0xa8, 0x00, 0xc0, 0x57, 0xc4, 0x92, 0xc7, 0xcc, 0xe0, 0x68, 0xb6, 0x75, 0x03,
|
||||
0xaa, 0xa1, 0x9a, 0xe5, 0x6a, 0xd4, 0x42, 0xde, 0xb4, 0xfa, 0xd3, 0xdf, 0x0e, 0xf1, 0xfc, 0x02,
|
||||
0x42, 0xdd, 0x2e, 0x66, 0x17, 0x8b, 0x61, 0x7b, 0x81, 0xc7, 0x01, 0x54, 0xc0, 0xc9, 0xbb, 0x50,
|
||||
0x93, 0x1b, 0xd0, 0xf5, 0x64, 0xe2, 0x4b, 0x84, 0x29, 0x21, 0x90, 0xc6, 0x78, 0xe3, 0x1f, 0xf2,
|
||||
0x42, 0x29, 0xcb, 0xac, 0xcb, 0x8e, 0xaf, 0x52, 0x8c, 0x1f, 0xe6, 0x81, 0x70, 0x61, 0x1b, 0xa6,
|
||||
0xef, 0x3f, 0x71, 0x3d, 0x6b, 0x69, 0xc7, 0x74, 0xb6, 0x8f, 0x64, 0x3a, 0xc6, 0x8f, 0x4a, 0x70,
|
||||
0x76, 0x51, 0x04, 0x6d, 0xec, 0x07, 0x03, 0xe6, 0x07, 0xc7, 0x7c, 0xbd, 0xdd, 0x4c, 0xae, 0x37,
|
||||
0x0c, 0x38, 0x71, 0xbd, 0xa9, 0x01, 0xa7, 0x58, 0x79, 0x6f, 0x41, 0x4d, 0xce, 0x79, 0x75, 0x59,
|
||||
0xae, 0x3c, 0x3c, 0x64, 0x6d, 0x8b, 0xc6, 0x08, 0xf2, 0x1e, 0x4c, 0xca, 0x7f, 0xb8, 0xaf, 0x0d,
|
||||
0xd3, 0x80, 0xb8, 0x8e, 0x7d, 0x0e, 0xa0, 0x09, 0x34, 0xf9, 0x06, 0xd4, 0xf8, 0xe2, 0xdc, 0xc6,
|
||||
0x26, 0x8d, 0x89, 0xb8, 0x9d, 0xc2, 0x0a, 0x81, 0xaa, 0x4b, 0x88, 0x28, 0xb9, 0x03, 0x97, 0xb9,
|
||||
0xdf, 0x6a, 0xec, 0xc0, 0x45, 0xee, 0x57, 0x75, 0xe0, 0x32, 0x0b, 0xfc, 0x29, 0xd4, 0x17, 0x1d,
|
||||
0xc7, 0x0d, 0x4c, 0x7e, 0x68, 0xf9, 0x32, 0x6f, 0xb3, 0xaf, 0xe7, 0xbe, 0x8e, 0x45, 0xfe, 0x98,
|
||||
0x3e, 0xd3, 0x75, 0xab, 0x02, 0x8d, 0x3f, 0x2e, 0x40, 0x9d, 0xdf, 0x1c, 0xef, 0xb9, 0xde, 0x13,
|
||||
0xd3, 0x3b, 0x9a, 0x70, 0x3a, 0x79, 0xa8, 0x17, 0x0f, 0x71, 0x09, 0x8b, 0x8f, 0xd4, 0xd2, 0x73,
|
||||
0x1c, 0xa9, 0x3c, 0xbc, 0xe5, 0x37, 0xf0, 0x72, 0x1c, 0x57, 0xe1, 0xed, 0x1b, 0xa1, 0xc6, 0x6f,
|
||||
0x16, 0x00, 0xbe, 0x7b, 0xe7, 0xce, 0x6b, 0xac, 0x20, 0xe3, 0x8f, 0xf2, 0x70, 0x46, 0xe6, 0x5b,
|
||||
0x94, 0xc6, 0xaa, 0x89, 0x30, 0xb9, 0x95, 0x8f, 0xf3, 0x48, 0x32, 0xa9, 0x45, 0x43, 0x1c, 0x99,
|
||||
0x87, 0xea, 0xca, 0x53, 0x3b, 0xc0, 0x90, 0x53, 0xe9, 0xac, 0x62, 0x12, 0xa6, 0xb6, 0x94, 0x84,
|
||||
0x74, 0xe4, 0xbd, 0x30, 0x93, 0x54, 0x8c, 0x37, 0x15, 0x67, 0x58, 0xc9, 0xcc, 0x26, 0x19, 0x7f,
|
||||
0x57, 0x82, 0xd2, 0xca, 0x53, 0xd6, 0x39, 0xe6, 0xa6, 0x51, 0x6e, 0xd6, 0xa5, 0x43, 0xde, 0xac,
|
||||
0x5f, 0x24, 0x9b, 0xfd, 0x61, 0x6c, 0xcf, 0x4a, 0xf2, 0xf3, 0x29, 0xcb, 0xa7, 0x3f, 0x1f, 0x5a,
|
||||
0xfa, 0xf8, 0x15, 0x43, 0x7e, 0x5c, 0x84, 0xe2, 0xe6, 0xd2, 0xc6, 0xc9, 0xba, 0x39, 0xd2, 0x75,
|
||||
0x73, 0x70, 0xea, 0xd1, 0x80, 0xca, 0xa2, 0xd0, 0x51, 0x35, 0xae, 0x94, 0x9a, 0x08, 0xa1, 0x12,
|
||||
0x63, 0x7c, 0x5e, 0x80, 0xda, 0xe6, 0xa0, 0xed, 0xef, 0xf9, 0x01, 0xeb, 0x1d, 0x73, 0x6b, 0x5e,
|
||||
0x96, 0xb1, 0x4d, 0x29, 0xd6, 0x06, 0xf6, 0xb9, 0x8a, 0x88, 0xe6, 0x7a, 0xe8, 0x19, 0x95, 0xdb,
|
||||
0x73, 0xe4, 0x19, 0x43, 0x7f, 0xf8, 0xb7, 0x05, 0x98, 0x5a, 0xea, 0xda, 0xcc, 0x09, 0x96, 0x6d,
|
||||
0x5f, 0xde, 0xad, 0x8f, 0xb9, 0x56, 0x0e, 0x97, 0x34, 0xf8, 0x1a, 0xd5, 0x76, 0xe3, 0xb7, 0x0a,
|
||||
0x50, 0x5f, 0x1c, 0x04, 0x3b, 0x8b, 0x01, 0x1e, 0x2e, 0xaf, 0xe5, 0x31, 0xff, 0xb3, 0x3c, 0x68,
|
||||
0x94, 0xf9, 0x2c, 0x08, 0x83, 0x95, 0x2d, 0xf7, 0x31, 0x73, 0x5e, 0x42, 0x94, 0xa0, 0xde, 0xf6,
|
||||
0x0b, 0x2f, 0x78, 0xdb, 0x0f, 0x95, 0x5a, 0x7c, 0xce, 0xa8, 0x87, 0xc7, 0x91, 0x3c, 0x08, 0x78,
|
||||
0x45, 0xa6, 0xf1, 0x12, 0xc2, 0xe1, 0xa3, 0x9c, 0xc6, 0x3f, 0xe7, 0x61, 0x66, 0xcb, 0xe3, 0x27,
|
||||
0xba, 0x25, 0x0f, 0xf6, 0x63, 0x6e, 0x97, 0xf1, 0x09, 0x1d, 0x73, 0x0b, 0xfd, 0x6b, 0x1e, 0x2e,
|
||||
0x26, 0x27, 0xf4, 0x2a, 0x78, 0x81, 0x7f, 0xc9, 0xc3, 0xb9, 0x6f, 0xdb, 0xc1, 0xce, 0xa0, 0x1d,
|
||||
0x65, 0x98, 0x5e, 0xbd, 0x19, 0x1d, 0xf3, 0x95, 0xf7, 0x93, 0x3c, 0x9c, 0x5d, 0x5f, 0x5d, 0x5e,
|
||||
0x7a, 0x55, 0x2c, 0x34, 0x36, 0x9f, 0x57, 0xc0, 0x3e, 0x9b, 0x8b, 0xf7, 0xd7, 0x5e, 0x25, 0xfb,
|
||||
0x24, 0xe6, 0x73, 0xcc, 0xed, 0xf3, 0x3b, 0x15, 0xa8, 0xf3, 0x00, 0x57, 0x26, 0x29, 0x5f, 0xeb,
|
||||
0x2b, 0xff, 0x3c, 0xd4, 0xa5, 0x1a, 0x30, 0xb6, 0x2c, 0xc7, 0xaf, 0x07, 0x3d, 0x01, 0x6e, 0x61,
|
||||
0x8c, 0xa9, 0x12, 0xf1, 0xd0, 0xeb, 0x3b, 0xcc, 0x6b, 0xab, 0xed, 0x15, 0xbb, 0xcc, 0x6b, 0x53,
|
||||
0x84, 0x92, 0xb5, 0xb8, 0x10, 0xb5, 0xb8, 0xb1, 0x8a, 0xef, 0x7e, 0x64, 0xc8, 0x8a, 0x0f, 0x99,
|
||||
0x3c, 0x89, 0x6b, 0x99, 0x7d, 0x5b, 0xbc, 0x18, 0x52, 0x1f, 0x0c, 0xa5, 0x39, 0xc9, 0x03, 0x98,
|
||||
0x0e, 0x61, 0xf1, 0x03, 0x9e, 0x6a, 0x86, 0xb8, 0xac, 0xa7, 0x3b, 0xe3, 0xac, 0xe4, 0x43, 0x98,
|
||||
0x0c, 0x81, 0x1f, 0xdb, 0xf8, 0xbc, 0x80, 0x8b, 0x7a, 0x63, 0x34, 0xd4, 0x2f, 0x44, 0xa2, 0x1e,
|
||||
0xdb, 0x89, 0x6e, 0xb3, 0x04, 0x83, 0x2a, 0x00, 0xe3, 0x4f, 0xc8, 0x10, 0x90, 0x2a, 0xb2, 0x25,
|
||||
0x18, 0xc8, 0x37, 0x50, 0x40, 0xdf, 0x75, 0x7c, 0x86, 0xc9, 0xbe, 0x3a, 0xf6, 0x1e, 0x60, 0xc9,
|
||||
0xcb, 0x93, 0x70, 0xd1, 0x61, 0x92, 0x20, 0x23, 0xeb, 0x00, 0x71, 0x52, 0x46, 0xb6, 0xde, 0x3d,
|
||||
0x77, 0xba, 0x48, 0x11, 0x61, 0xfc, 0x5f, 0x01, 0xce, 0x2c, 0xf6, 0xfb, 0x27, 0xaf, 0x74, 0x5e,
|
||||
0x56, 0x63, 0xc3, 0x1c, 0xc0, 0xc6, 0xa0, 0xdd, 0xb5, 0x3b, 0x4a, 0x97, 0x0a, 0xb6, 0x0d, 0xf5,
|
||||
0x11, 0x2a, 0x1a, 0x55, 0x14, 0x12, 0xe3, 0xf3, 0xa2, 0x6a, 0x01, 0x7c, 0x9d, 0x70, 0x62, 0x81,
|
||||
0xf2, 0xa1, 0x5c, 0xe1, 0x69, 0x55, 0x99, 0xb2, 0x89, 0x4f, 0x56, 0x8e, 0xc2, 0x0e, 0xda, 0x0e,
|
||||
0x47, 0xb5, 0x6c, 0x8b, 0xa6, 0x68, 0x8d, 0xff, 0xce, 0xc3, 0x74, 0x6c, 0x8e, 0x97, 0x71, 0x38,
|
||||
0xcc, 0x01, 0x88, 0x8c, 0x41, 0x94, 0xd5, 0x3f, 0x25, 0x56, 0x84, 0x8f, 0x50, 0xd9, 0x48, 0x16,
|
||||
0x93, 0x44, 0x29, 0xbe, 0x62, 0x66, 0x8a, 0xef, 0x26, 0x54, 0xa9, 0xf9, 0xe4, 0x93, 0x01, 0xf3,
|
||||
0xf6, 0x64, 0xda, 0x0b, 0xf3, 0x5a, 0x9e, 0xf9, 0xa4, 0xf5, 0x03, 0x0e, 0xa4, 0x11, 0x9a, 0x18,
|
||||
0x51, 0xf3, 0x83, 0x92, 0xc9, 0x11, 0xcd, 0x0f, 0x61, 0xcb, 0x83, 0xf1, 0x87, 0x05, 0x98, 0x5a,
|
||||
0x36, 0x03, 0xb3, 0x6d, 0xfa, 0x71, 0xcb, 0xc0, 0x37, 0xe1, 0x4c, 0x08, 0xe3, 0xe6, 0xb1, 0xa3,
|
||||
0x07, 0xd0, 0xa7, 0x47, 0x43, 0x1d, 0xac, 0x76, 0xcb, 0x17, 0x50, 0x9a, 0x26, 0x23, 0xbf, 0x1c,
|
||||
0x4b, 0x8b, 0x1e, 0xc6, 0x16, 0xe2, 0x4d, 0x60, 0xb5, 0x5b, 0x7d, 0x09, 0xa6, 0x63, 0x84, 0xe4,
|
||||
0x16, 0xd4, 0x43, 0xd8, 0x43, 0xba, 0x2a, 0xe7, 0x8f, 0x83, 0xb6, 0xda, 0xad, 0x81, 0x67, 0x53,
|
||||
0x15, 0x4d, 0xe6, 0x60, 0x32, 0xfc, 0x57, 0xc9, 0x01, 0x62, 0x5d, 0xc5, 0x6a, 0x8b, 0xe7, 0xee,
|
||||
0x09, 0x02, 0x95, 0x01, 0x77, 0x48, 0x39, 0xc1, 0x80, 0xaf, 0xcf, 0x13, 0x04, 0xc6, 0x4f, 0x8a,
|
||||
0x30, 0x13, 0x4f, 0xf0, 0xc4, 0x43, 0xbe, 0x9c, 0xfd, 0x19, 0x67, 0xdb, 0x2a, 0xcf, 0x51, 0x75,
|
||||
0x6c, 0x40, 0x35, 0x34, 0x85, 0x2c, 0x93, 0x44, 0x57, 0xc5, 0xf4, 0xf2, 0x4d, 0xab, 0x3e, 0xc4,
|
||||
0x1b, 0x5f, 0x14, 0xc6, 0xec, 0x29, 0x36, 0xca, 0xb1, 0xb4, 0xa7, 0xaa, 0x91, 0xd2, 0x8b, 0x69,
|
||||
0x84, 0xcc, 0xc3, 0xa9, 0xf0, 0x6f, 0xe1, 0x51, 0xca, 0x4a, 0x5b, 0x65, 0x5b, 0x3a, 0x94, 0x24,
|
||||
0x89, 0xf1, 0xbb, 0x05, 0x20, 0x29, 0x2d, 0x1e, 0xdb, 0xc7, 0x31, 0x2f, 0x41, 0x87, 0xc6, 0x5f,
|
||||
0xe5, 0x61, 0x7a, 0xac, 0x5f, 0x8b, 0xbc, 0x0f, 0x20, 0x20, 0x4a, 0xef, 0x15, 0xf6, 0x5c, 0xc4,
|
||||
0x3d, 0x5c, 0xc2, 0x47, 0x29, 0x64, 0x64, 0x0e, 0xaa, 0xe2, 0xbf, 0xe8, 0x57, 0x23, 0xd2, 0x2c,
|
||||
0x83, 0x81, 0x6d, 0xd1, 0x88, 0x28, 0xfe, 0x0a, 0xfe, 0x50, 0x49, 0x31, 0x93, 0x25, 0xd8, 0xeb,
|
||||
0x47, 0x5f, 0xe1, 0x64, 0xc6, 0x17, 0x79, 0x98, 0x8c, 0x06, 0xbc, 0x68, 0x1d, 0x95, 0xe9, 0x2a,
|
||||
0xb2, 0xf5, 0xad, 0xf8, 0xac, 0xd6, 0xb7, 0x94, 0x43, 0x90, 0xbd, 0x6e, 0xff, 0x98, 0x87, 0x33,
|
||||
0x11, 0xed, 0x11, 0xb6, 0x3d, 0x1d, 0x7a, 0x22, 0x3f, 0xbe, 0x00, 0xe5, 0x75, 0x87, 0xad, 0x3f,
|
||||
0x22, 0x77, 0x94, 0x1e, 0x4b, 0x39, 0xfe, 0x69, 0x75, 0x1c, 0x88, 0x68, 0xe6, 0xa8, 0xd2, 0x89,
|
||||
0xb9, 0xa0, 0xf6, 0xc2, 0xc9, 0xb1, 0x13, 0x95, 0x47, 0x60, 0x9a, 0x39, 0xaa, 0xf6, 0xcc, 0x2d,
|
||||
0xa8, 0xcd, 0x62, 0x72, 0xdc, 0x09, 0x2e, 0x81, 0x09, 0xb9, 0xa4, 0x76, 0xd7, 0xb2, 0x7a, 0xb3,
|
||||
0xd2, 0x2f, 0xca, 0xc6, 0x29, 0x9a, 0x39, 0x9a, 0xdd, 0xd3, 0x95, 0xf8, 0x6d, 0x00, 0x79, 0xa4,
|
||||
0xcc, 0xa4, 0x36, 0x30, 0xe2, 0x9a, 0x39, 0x9a, 0xfc, 0x1d, 0x81, 0xbb, 0x89, 0x87, 0xdd, 0xf2,
|
||||
0x1c, 0x39, 0x9b, 0x62, 0xe5, 0xa8, 0x66, 0x8e, 0xa6, 0x9e, 0x80, 0x27, 0x5e, 0x19, 0xcb, 0x93,
|
||||
0x24, 0xfd, 0x51, 0xc4, 0x29, 0x1f, 0x15, 0x2f, 0x92, 0x7f, 0x35, 0xf5, 0x24, 0x57, 0x96, 0xd4,
|
||||
0xcf, 0xa5, 0x98, 0x05, 0xb2, 0x99, 0xa3, 0xa9, 0x07, 0xbc, 0xb3, 0xe1, 0xe3, 0x53, 0xd9, 0x95,
|
||||
0x74, 0x5a, 0xc9, 0x74, 0xd8, 0x9f, 0x71, 0x2d, 0x85, 0x8f, 0x53, 0x17, 0xd4, 0x47, 0x87, 0xf2,
|
||||
0x79, 0x18, 0x49, 0x7d, 0x65, 0xc5, 0xb1, 0xb8, 0x75, 0x14, 0xff, 0xfb, 0x51, 0xfa, 0xad, 0x8f,
|
||||
0x7c, 0xf4, 0x75, 0x3e, 0xc5, 0x29, 0xb1, 0xcd, 0x1c, 0x4d, 0xbf, 0x0d, 0xba, 0x9b, 0x78, 0x67,
|
||||
0x22, 0xa3, 0xcb, 0xb4, 0x56, 0x39, 0x4a, 0xd1, 0x2a, 0xbe, 0x48, 0xf9, 0x28, 0xfd, 0xf0, 0x41,
|
||||
0x3b, 0x95, 0xf9, 0x69, 0x89, 0x55, 0x3e, 0x1d, 0x3e, 0x94, 0xb8, 0x9b, 0x68, 0xad, 0xd7, 0x4e,
|
||||
0x67, 0x7f, 0xda, 0x0c, 0x4c, 0xf5, 0xd3, 0xa2, 0x09, 0x3f, 0xd1, 0xe4, 0xad, 0x9d, 0xc9, 0x34,
|
||||
0x28, 0xe2, 0x14, 0x83, 0x8a, 0x86, 0xf0, 0xbb, 0x89, 0x5e, 0x2e, 0x6d, 0x2a, 0xf9, 0x51, 0x05,
|
||||
0xc5, 0x3f, 0xaa, 0x76, 0x7d, 0x2d, 0xa8, 0x2d, 0x4e, 0xda, 0x74, 0xd2, 0x40, 0x31, 0x86, 0x1b,
|
||||
0x48, 0x69, 0x85, 0xd2, 0xb1, 0x7d, 0x42, 0x23, 0x48, 0x5e, 0x8f, 0x46, 0xb8, 0xb4, 0xd1, 0xcc,
|
||||
0x51, 0x6c, 0xac, 0x30, 0x44, 0x63, 0x8e, 0x76, 0x16, 0x29, 0x26, 0x43, 0x0a, 0x0e, 0x6b, 0xe6,
|
||||
0xa8, 0x68, 0xda, 0xb9, 0xa3, 0xd4, 0xee, 0xb5, 0x99, 0xa4, 0x8b, 0x88, 0x10, 0xdc, 0x45, 0xc4,
|
||||
0x15, 0xfe, 0x7b, 0xe3, 0xf5, 0x6d, 0xed, 0x5c, 0xf2, 0xac, 0x4b, 0xe3, 0x9b, 0x39, 0x3a, 0x5e,
|
||||
0x13, 0xbf, 0x9b, 0x28, 0xf9, 0x6a, 0xe7, 0x93, 0xea, 0x52, 0x50, 0x5c, 0x5d, 0x6a, 0x71, 0x78,
|
||||
0x3d, 0xb3, 0x91, 0x52, 0xbb, 0x80, 0x02, 0xde, 0x88, 0x04, 0x8c, 0x93, 0x34, 0x73, 0x34, 0xb3,
|
||||
0x05, 0xf3, 0xd3, 0xfd, 0x0b, 0xaf, 0x9a, 0x86, 0x52, 0xaf, 0x2a, 0x9b, 0x2b, 0x93, 0xae, 0x99,
|
||||
0xa3, 0xfb, 0x17, 0x6f, 0x17, 0xd4, 0x1a, 0xa8, 0x76, 0x31, 0x69, 0xdf, 0x18, 0xc3, 0xed, 0xab,
|
||||
0xd4, 0x4a, 0x17, 0xd4, 0x92, 0xa3, 0x76, 0x69, 0x9c, 0x2b, 0x76, 0xaa, 0x4a, 0x69, 0x92, 0x66,
|
||||
0x57, 0xf8, 0xb4, 0x37, 0x90, 0xff, 0x72, 0xc8, 0x9f, 0x45, 0xd3, 0xcc, 0xd1, 0xec, 0xea, 0x20,
|
||||
0xcd, 0x2e, 0xb2, 0x69, 0x97, 0x0f, 0x92, 0x19, 0x8d, 0x2e, 0xbb, 0x40, 0x67, 0x1e, 0x50, 0xe7,
|
||||
0xd2, 0xde, 0x4c, 0x26, 0xa2, 0xf6, 0x25, 0x6c, 0xe6, 0xe8, 0x01, 0xd5, 0xb2, 0x87, 0xfb, 0x14,
|
||||
0x9d, 0xb4, 0x2b, 0xc9, 0xde, 0xa5, 0x4c, 0xa2, 0x66, 0x8e, 0xee, 0x53, 0xb2, 0x7a, 0xb8, 0x4f,
|
||||
0xe5, 0x47, 0xd3, 0x0f, 0x14, 0x1b, 0xe9, 0x63, 0x9f, 0xba, 0xd1, 0x7a, 0x66, 0xf9, 0x45, 0xbb,
|
||||
0x9a, 0x5c, 0xd5, 0x19, 0x24, 0x7c, 0x55, 0x67, 0x15, 0x6e, 0xd6, 0x33, 0xeb, 0x1f, 0xda, 0xb5,
|
||||
0x03, 0x04, 0x46, 0x63, 0xcc, 0xac, 0x9c, 0xac, 0x67, 0x16, 0x20, 0x34, 0x23, 0x29, 0x30, 0x83,
|
||||
0x84, 0x0b, 0xcc, 0x2a, 0x5d, 0xac, 0x67, 0x56, 0x00, 0xb4, 0xeb, 0x07, 0x08, 0x8c, 0x47, 0x98,
|
||||
0x55, 0x3b, 0xb8, 0x9b, 0x48, 0xc1, 0x6b, 0x6f, 0x25, 0x5d, 0x8a, 0x82, 0xe2, 0x2e, 0x45, 0x4d,
|
||||
0xd6, 0x2f, 0x8d, 0x65, 0x2d, 0xb5, 0xb7, 0x93, 0x01, 0x40, 0x0a, 0xdd, 0xcc, 0xd1, 0xb1, 0x3c,
|
||||
0xe7, 0xd2, 0x58, 0xe2, 0x4d, 0xbb, 0xb1, 0x9f, 0x10, 0x44, 0x27, 0x85, 0x88, 0x54, 0xdd, 0x6a,
|
||||
0x46, 0xba, 0x48, 0x7b, 0x27, 0x79, 0x13, 0x1c, 0x23, 0x68, 0xe6, 0x68, 0x46, 0x92, 0x89, 0x66,
|
||||
0x67, 0x1b, 0xb4, 0xd9, 0xe4, 0xb6, 0xcd, 0xa2, 0xe1, 0xdb, 0x36, 0x33, 0x53, 0xb1, 0x96, 0x15,
|
||||
0xab, 0x69, 0x37, 0x93, 0x77, 0xb6, 0x71, 0x0a, 0x7e, 0x67, 0xcb, 0x88, 0xf1, 0x68, 0x76, 0xfc,
|
||||
0xac, 0xfd, 0xc2, 0x81, 0x23, 0x44, 0x9a, 0x8c, 0x11, 0x8a, 0xd8, 0x3b, 0xbe, 0x56, 0x3d, 0xec,
|
||||
0x77, 0x5d, 0xd3, 0xd2, 0xde, 0xcd, 0xbc, 0x56, 0x09, 0xa4, 0x72, 0xad, 0x12, 0x00, 0x7e, 0x01,
|
||||
0x50, 0x63, 0x19, 0xed, 0x56, 0xf2, 0x02, 0xa0, 0xe2, 0xf8, 0x05, 0x20, 0x11, 0xf7, 0x2c, 0x8d,
|
||||
0x45, 0x10, 0xda, 0x7b, 0xc9, 0x05, 0x90, 0x42, 0xf3, 0x05, 0x90, 0x02, 0x35, 0x26, 0xa0, 0xbc,
|
||||
0xc2, 0x89, 0x8d, 0x3f, 0xc9, 0xc3, 0xe4, 0x66, 0xe0, 0x31, 0xb3, 0x27, 0x53, 0x16, 0x97, 0xa0,
|
||||
0x2a, 0x06, 0x19, 0xfe, 0x96, 0x22, 0x8d, 0xfe, 0x27, 0x37, 0xe0, 0xf4, 0x9a, 0xe9, 0x07, 0xc8,
|
||||
0xa9, 0xfc, 0x4c, 0x0d, 0x4d, 0x41, 0xc9, 0x9a, 0xa0, 0x13, 0x7c, 0xf8, 0x73, 0x01, 0xc5, 0x67,
|
||||
0xbe, 0xcd, 0xa9, 0xf2, 0x30, 0x03, 0x1f, 0xe4, 0xa4, 0x78, 0x8d, 0x51, 0x1e, 0xc6, 0xd4, 0xf7,
|
||||
0xe2, 0x11, 0xd3, 0xfa, 0xd8, 0xef, 0x47, 0xca, 0x00, 0xe4, 0x6b, 0x46, 0xe1, 0x63, 0xbf, 0x3e,
|
||||
0x79, 0x1d, 0x8a, 0x0f, 0x57, 0x97, 0xd5, 0xe7, 0x3f, 0xc9, 0x9f, 0xd4, 0xe4, 0x58, 0xf2, 0x4e,
|
||||
0x74, 0x3b, 0x7e, 0x48, 0xd7, 0x64, 0xbe, 0x02, 0x9f, 0xf7, 0x0f, 0xbc, 0x2e, 0x55, 0x50, 0x8d,
|
||||
0xa9, 0x2f, 0xff, 0xf3, 0x4a, 0xee, 0xcb, 0xaf, 0xae, 0xe4, 0x7f, 0xfa, 0xd5, 0x95, 0xfc, 0x7f,
|
||||
0x7c, 0x75, 0x25, 0xdf, 0xae, 0xa0, 0xb2, 0xde, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb1,
|
||||
0x12, 0x46, 0xe4, 0x6f, 0x54, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Metadata) Marshal() (dAtA []byte, err error) {
|
||||
|
@ -4107,6 +4111,13 @@ func (m *UserMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Impersonator) > 0 {
|
||||
i -= len(m.Impersonator)
|
||||
copy(dAtA[i:], m.Impersonator)
|
||||
i = encodeVarintEvents(dAtA, i, uint64(len(m.Impersonator)))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
if len(m.Login) > 0 {
|
||||
i -= len(m.Login)
|
||||
copy(dAtA[i:], m.Login)
|
||||
|
@ -9279,6 +9290,10 @@ func (m *UserMetadata) Size() (n int) {
|
|||
if l > 0 {
|
||||
n += 1 + l + sovEvents(uint64(l))
|
||||
}
|
||||
l = len(m.Impersonator)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovEvents(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
|
@ -11714,6 +11729,38 @@ func (m *UserMetadata) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
m.Login = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Impersonator", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowEvents
|
||||
}
|
||||
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 ErrInvalidLengthEvents
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthEvents
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Impersonator = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipEvents(dAtA[iNdEx:])
|
||||
|
|
|
@ -46,6 +46,9 @@ message UserMetadata {
|
|||
|
||||
// Login is OS login
|
||||
string Login = 2 [ (gogoproto.jsontag) = "login,omitempty" ];
|
||||
|
||||
// Impersonator is a user acting on behalf of another user
|
||||
string Impersonator = 3 [ (gogoproto.jsontag) = "impersonator,omitempty" ];
|
||||
}
|
||||
|
||||
// Server is a server metadata
|
||||
|
|
|
@ -111,6 +111,11 @@ type Role interface {
|
|||
GetDatabaseUsers(RoleConditionType) []string
|
||||
// SetDatabaseUsers sets a list of database users this role is allowed or denied access to.
|
||||
SetDatabaseUsers(RoleConditionType, []string)
|
||||
|
||||
// GetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
|
||||
GetImpersonateConditions(rct RoleConditionType) ImpersonateConditions
|
||||
// SetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
|
||||
SetImpersonateConditions(rct RoleConditionType, cond ImpersonateConditions)
|
||||
}
|
||||
|
||||
// NewRole constructs new standard role
|
||||
|
@ -179,6 +184,9 @@ func (r *RoleV3) Equals(other Role) bool {
|
|||
if !r.GetKubernetesLabels(condition).Equals(other.GetKubernetesLabels(condition)) {
|
||||
return false
|
||||
}
|
||||
if !r.GetImpersonateConditions(condition).Equals(other.GetImpersonateConditions(condition)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -472,6 +480,27 @@ func (r *RoleV3) SetDatabaseUsers(rct RoleConditionType, values []string) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
|
||||
func (r *RoleV3) GetImpersonateConditions(rct RoleConditionType) ImpersonateConditions {
|
||||
cond := r.Spec.Deny.Impersonate
|
||||
if rct == Allow {
|
||||
cond = r.Spec.Allow.Impersonate
|
||||
}
|
||||
if cond == nil {
|
||||
return ImpersonateConditions{}
|
||||
}
|
||||
return *cond
|
||||
}
|
||||
|
||||
// SetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
|
||||
func (r *RoleV3) SetImpersonateConditions(rct RoleConditionType, cond ImpersonateConditions) {
|
||||
if rct == Allow {
|
||||
r.Spec.Allow.Impersonate = &cond
|
||||
} else {
|
||||
r.Spec.Deny.Impersonate = &cond
|
||||
}
|
||||
}
|
||||
|
||||
// GetRules gets all allow or deny rules.
|
||||
func (r *RoleV3) GetRules(rct RoleConditionType) []Rule {
|
||||
if rct == Allow {
|
||||
|
@ -592,7 +621,19 @@ func (r *RoleV3) CheckAndSetDefaults() error {
|
|||
return trace.BadParameter("failed to process 'deny' rule %v: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
if r.Spec.Allow.Impersonate != nil {
|
||||
if err := r.Spec.Allow.Impersonate.CheckAndSetDefaults(); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
if r.Spec.Deny.Impersonate != nil {
|
||||
if r.Spec.Deny.Impersonate.Where != "" {
|
||||
return trace.BadParameter("'where' is not supported in deny.impersonate conditions")
|
||||
}
|
||||
if err := r.Spec.Deny.Impersonate.CheckAndSetDefaults(); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -651,6 +692,37 @@ func (r *RoleConditions) Equals(o RoleConditions) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// IsEmpty returns true if conditions are unspecified
|
||||
func (i ImpersonateConditions) IsEmpty() bool {
|
||||
return len(i.Users) == 0 || len(i.Roles) == 0
|
||||
}
|
||||
|
||||
// Equals returns true if the impersonate conditions (logins, roles
|
||||
// and rules) are equal and false if they are not.
|
||||
func (i ImpersonateConditions) Equals(o ImpersonateConditions) bool {
|
||||
if !utils.StringSlicesEqual(i.Users, o.Users) {
|
||||
return false
|
||||
}
|
||||
if !utils.StringSlicesEqual(i.Roles, o.Roles) {
|
||||
return false
|
||||
}
|
||||
if i.Where != o.Where {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CheckAndSetDefaults checks and sets default values
|
||||
func (i ImpersonateConditions) CheckAndSetDefaults() error {
|
||||
if len(i.Users) != 0 && len(i.Roles) == 0 {
|
||||
return trace.BadParameter("please set both impersonate.users and impersonate.roles")
|
||||
}
|
||||
if len(i.Users) == 0 && len(i.Roles) != 0 {
|
||||
return trace.BadParameter("please set both impersonate.users and impersonate.roles")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRule creates a rule based on a resource name and a list of verbs
|
||||
func NewRule(resource string, verbs []string) Rule {
|
||||
return Rule{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -965,6 +965,10 @@ message RoleConditions {
|
|||
repeated string DatabaseNames = 12 [ (gogoproto.jsontag) = "db_names,omitempty" ];
|
||||
// DatabaseUsers is a list of databaes users this role is allowed to connect as.
|
||||
repeated string DatabaseUsers = 13 [ (gogoproto.jsontag) = "db_users,omitempty" ];
|
||||
|
||||
// Impersonate specifies what users and roles this role is allowed to impersonate
|
||||
// by issuing certificates or other possible means.
|
||||
ImpersonateConditions Impersonate = 14 [ (gogoproto.jsontag) = "impersonate,omitempty" ];
|
||||
}
|
||||
|
||||
// AccessRequestConditions is a matcher for allow/deny restrictions on
|
||||
|
@ -1018,6 +1022,18 @@ message Rule {
|
|||
repeated string Actions = 4 [ (gogoproto.jsontag) = "actions,omitempty" ];
|
||||
}
|
||||
|
||||
// ImpersonateConditions specifies whether users are allowed
|
||||
// to issue certificates for other users or groups.
|
||||
message ImpersonateConditions {
|
||||
// Users is a list of resources this role is allowed to impersonate,
|
||||
// could be an empty list or a Wildcard pattern
|
||||
repeated string Users = 1 [ (gogoproto.jsontag) = "users,omitempty" ];
|
||||
// Roles is a list of resources this role is allowed to impersonate
|
||||
repeated string Roles = 2 [ (gogoproto.jsontag) = "roles,omitempty" ];
|
||||
// Where specifies optional advanced matcher
|
||||
string Where = 3 [ (gogoproto.jsontag) = "where,omitempty" ];
|
||||
}
|
||||
|
||||
// BoolValue is a wrapper around bool, used in cases
|
||||
// whenever bool value can have different default value when missing
|
||||
message BoolValue { bool Value = 1; }
|
||||
|
|
|
@ -448,6 +448,9 @@ const (
|
|||
// CertExtensionClientIP is used to embed the IP of the client that created
|
||||
// the certificate.
|
||||
CertExtensionClientIP = "client-ip"
|
||||
// CertExtensionImpersonator is set when one user has requested certificates
|
||||
// for another user
|
||||
CertExtensionImpersonator = "impersonator"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -433,6 +433,9 @@ type certs struct {
|
|||
type certRequest struct {
|
||||
// user is a user to generate certificate for
|
||||
user services.User
|
||||
// impersonator is a user who generates the certificate,
|
||||
// is set when different from the user in the certificate
|
||||
impersonator string
|
||||
// checker is used to perform RBAC checks.
|
||||
checker services.AccessChecker
|
||||
// ttl is Duration of the certificate
|
||||
|
@ -677,11 +680,12 @@ func (a *Server) generateUserCert(req certRequest) (*certs, error) {
|
|||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
sshCert, err := a.Authority.GenerateUserCert(services.UserCertParams{
|
||||
params := services.UserCertParams{
|
||||
PrivateCASigningKey: privateKey,
|
||||
CASigningAlg: sshutils.GetSigningAlgName(ca),
|
||||
PublicUserKey: req.publicKey,
|
||||
Username: req.user.GetName(),
|
||||
Impersonator: req.impersonator,
|
||||
AllowedLogins: allowedLogins,
|
||||
TTL: sessionTTL,
|
||||
Roles: req.checker.RoleNames(),
|
||||
|
@ -694,7 +698,8 @@ func (a *Server) generateUserCert(req certRequest) (*certs, error) {
|
|||
ActiveRequests: req.activeRequests,
|
||||
MFAVerified: req.mfaVerified,
|
||||
ClientIP: req.clientIP,
|
||||
})
|
||||
}
|
||||
sshCert, err := a.Authority.GenerateUserCert(params)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -731,6 +736,7 @@ func (a *Server) generateUserCert(req certRequest) (*certs, error) {
|
|||
}
|
||||
identity := tlsca.Identity{
|
||||
Username: req.user.GetName(),
|
||||
Impersonator: req.impersonator,
|
||||
Groups: req.checker.RoleNames(),
|
||||
Principals: allowedLogins,
|
||||
Usage: req.usage,
|
||||
|
@ -1105,7 +1111,8 @@ func (a *Server) GenerateToken(ctx context.Context, req GenerateTokenRequest) (s
|
|||
Code: events.TrustedClusterTokenCreateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: user,
|
||||
User: user,
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
}); err != nil {
|
||||
log.WithError(err).Warn("Failed to emit trusted cluster token create event.")
|
||||
|
@ -1666,7 +1673,8 @@ func (a *Server) DeleteRole(ctx context.Context, name string) error {
|
|||
Code: events.RoleDeletedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: name,
|
||||
|
@ -1743,7 +1751,8 @@ func (a *Server) CreateAccessRequest(ctx context.Context, req services.AccessReq
|
|||
Code: events.AccessRequestCreateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: req.GetUser(),
|
||||
User: req.GetUser(),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
Roles: req.GetRoles(),
|
||||
RequestID: req.GetName(),
|
||||
|
|
|
@ -1194,21 +1194,51 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC
|
|||
var roles []string
|
||||
var traits wrappers.Traits
|
||||
|
||||
switch {
|
||||
case a.hasBuiltinRole(string(teleport.RoleAdmin)):
|
||||
// If it's an admin generating the certificate, the roles and traits for
|
||||
// the user have to be fetched from the backend. This should be safe since
|
||||
// this is typically done against a local user.
|
||||
user, err := a.GetUser(req.Username, false)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
// this prevents clients who have no chance at getting a cert and impersonating anyone
|
||||
// from enumerating local users and hitting database
|
||||
if !a.hasBuiltinRole(string(teleport.RoleAdmin)) && !a.context.Checker.CanImpersonateSomeone() && req.Username != a.context.User.GetName() {
|
||||
return nil, trace.AccessDenied("access denied: impersonation is not allowed")
|
||||
}
|
||||
|
||||
// Prohibit recursive impersonation behavior:
|
||||
//
|
||||
// Alice can impersonate Bob
|
||||
// Bob can impersonate Grace <- this code block prohibits the escape
|
||||
//
|
||||
// Allow cases:
|
||||
//
|
||||
// Alice can impersonate Bob
|
||||
//
|
||||
// Bob (impersonated by Alice) can renew the cert with route to cluster
|
||||
//
|
||||
if a.context.Identity != nil && a.context.Identity.GetIdentity().Impersonator != "" {
|
||||
if len(req.AccessRequests) > 0 {
|
||||
return nil, trace.AccessDenied("access denied: impersonated user can not request new roles")
|
||||
}
|
||||
roles = user.GetRoles()
|
||||
traits = user.GetTraits()
|
||||
case req.Username == a.context.User.GetName():
|
||||
// user is requesting TTL for themselves,
|
||||
// limit the TTL to the duration of the session, to prevent
|
||||
// users renewing their certificates forever
|
||||
if req.Username != a.context.User.GetName() {
|
||||
return nil, trace.AccessDenied("access denied: impersonated user can not impersonate anyone else")
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the user and role set for whom the certificate will be generated.
|
||||
// This should be safe since this is typically done against a local user.
|
||||
//
|
||||
// This call bypasses RBAC check for users read on purpose.
|
||||
// Users who are allowed to impersonate other users might not have
|
||||
// permissions to read user data.
|
||||
user, err := a.authServer.GetUser(req.Username, false)
|
||||
if err != nil {
|
||||
log.WithError(err).Debugf("Could not impersonate user %v. The user could not be fetched from local store.", req.Username)
|
||||
return nil, trace.AccessDenied("access denied")
|
||||
}
|
||||
if user.GetCreatedBy().Connector != nil {
|
||||
log.Warningf("User %v tried to issue a cert for externally managed user %v, this is not supported.", a.context.User.GetName(), req.Username)
|
||||
return nil, trace.AccessDenied("access denied")
|
||||
}
|
||||
|
||||
// For users renewing certificates limit the TTL to the duration of the session, to prevent
|
||||
// users renewing certificates forever.
|
||||
if req.Username == a.context.User.GetName() {
|
||||
expires := a.context.Identity.GetIdentity().Expires
|
||||
if expires.IsZero() {
|
||||
log.Warningf("Encountered identity with no expiry: %v and denied request. Must be internal logic error.", a.context.Identity)
|
||||
|
@ -1220,31 +1250,22 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC
|
|||
if req.Expires.Before(a.authServer.GetClock().Now()) {
|
||||
return nil, trace.AccessDenied("access denied: client credentials have expired, please relogin.")
|
||||
}
|
||||
// If the user is generating a certificate, the roles and traits come from
|
||||
// the logged in identity.
|
||||
}
|
||||
|
||||
// If the user is generating a certificate, the roles and traits come from the logged in identity.
|
||||
if req.Username == a.context.User.GetName() {
|
||||
roles, traits, err = services.ExtractFromIdentity(a.authServer, a.context.Identity.GetIdentity())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
default:
|
||||
err := trace.AccessDenied("user %q has requested to generate certs for %q.", a.context.User.GetName(), req.Username)
|
||||
log.Warning(err)
|
||||
if err := a.authServer.emitter.EmitAuditEvent(a.CloseContext(), &events.UserLogin{
|
||||
Metadata: events.Metadata{
|
||||
Type: events.UserLoginEvent,
|
||||
Code: events.UserLocalLoginFailureCode,
|
||||
},
|
||||
Method: events.LoginMethodClientCert,
|
||||
Status: events.Status{
|
||||
Success: false,
|
||||
Error: trace.Unwrap(err).Error(),
|
||||
UserMessage: err.Error(),
|
||||
},
|
||||
}); err != nil {
|
||||
log.WithError(err).Warn("Failed to emit local login failure event.")
|
||||
} else {
|
||||
// Do not allow combining impersonation and access requests
|
||||
if len(req.AccessRequests) > 0 {
|
||||
log.WithError(err).Warningf("User %v tried to issue a cert for %v and added access requests. This is not supported.", a.context.User.GetName(), req.Username)
|
||||
return nil, trace.AccessDenied("access denied")
|
||||
}
|
||||
// this error is vague on purpose, it should not happen unless someone is trying something out of loop
|
||||
return nil, trace.AccessDenied("this request can be only executed by an admin")
|
||||
roles = user.GetRoles()
|
||||
traits = user.GetTraits()
|
||||
}
|
||||
|
||||
if len(req.AccessRequests) > 0 {
|
||||
|
@ -1284,14 +1305,45 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC
|
|||
roles = utils.Deduplicate(roles)
|
||||
}
|
||||
|
||||
// Extract the user and role set for whom the certificate will be generated.
|
||||
user, err := a.GetUser(req.Username, false)
|
||||
parsedRoles, err := services.FetchRoleList(roles, a.authServer, traits)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
checker, err := services.FetchRoles(roles, a.authServer, traits)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
// add implicit roles to the set and build a checker
|
||||
checker := services.NewRoleSet(parsedRoles...)
|
||||
|
||||
switch {
|
||||
case a.hasBuiltinRole(string(teleport.RoleAdmin)):
|
||||
// builtin admins can impersonate anyone
|
||||
// this is required for local tctl commands to work
|
||||
case req.Username == a.context.User.GetName():
|
||||
// users can impersonate themselves
|
||||
default:
|
||||
// check if this user is allowed to impersonate other users
|
||||
err = a.context.Checker.CheckImpersonate(a.context.User, user, parsedRoles)
|
||||
// adjust session TTL based on the impersonated role set limit
|
||||
ttl := req.Expires.Sub(a.authServer.GetClock().Now())
|
||||
ttl = checker.AdjustSessionTTL(ttl)
|
||||
req.Expires = a.authServer.GetClock().Now().Add(ttl)
|
||||
if err != nil {
|
||||
log.Warning(err)
|
||||
err := trace.AccessDenied("user %q has requested to generate certs for %q.", a.context.User.GetName(), roles)
|
||||
if err := a.authServer.emitter.EmitAuditEvent(a.CloseContext(), &events.UserLogin{
|
||||
Metadata: events.Metadata{
|
||||
Type: events.UserLoginEvent,
|
||||
Code: events.UserLocalLoginFailureCode,
|
||||
},
|
||||
Method: events.LoginMethodClientCert,
|
||||
Status: events.Status{
|
||||
Success: false,
|
||||
Error: trace.Unwrap(err).Error(),
|
||||
UserMessage: err.Error(),
|
||||
},
|
||||
}); err != nil {
|
||||
log.WithError(err).Warn("Failed to emit local login failure event.")
|
||||
}
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate certificate, note that the roles TTL will be ignored because
|
||||
|
@ -1314,6 +1366,12 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC
|
|||
AccessRequests: req.AccessRequests,
|
||||
},
|
||||
}
|
||||
if user.GetName() != a.context.User.GetName() {
|
||||
certReq.impersonator = a.context.User.GetName()
|
||||
} else if a.context.Identity != nil && a.context.Identity.GetIdentity().Impersonator != "" {
|
||||
// impersonating users can receive new certs
|
||||
certReq.impersonator = a.context.Identity.GetIdentity().Impersonator
|
||||
}
|
||||
switch req.Usage {
|
||||
case proto.UserCertsRequest_Database:
|
||||
certReq.usage = []string{teleport.UsageDatabaseOnly}
|
||||
|
|
|
@ -72,7 +72,8 @@ func (a *Server) upsertGithubConnector(ctx context.Context, connector services.G
|
|||
Code: events.GithubConnectorCreatedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connector.GetName(),
|
||||
|
@ -96,7 +97,8 @@ func (a *Server) deleteGithubConnector(ctx context.Context, connectorName string
|
|||
Code: events.GithubConnectorDeletedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connectorName,
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/api/client"
|
||||
"github.com/gravitational/teleport/api/constants"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
authority "github.com/gravitational/teleport/lib/auth/testauthority"
|
||||
"github.com/gravitational/teleport/lib/backend"
|
||||
"github.com/gravitational/teleport/lib/backend/memory"
|
||||
|
@ -633,6 +634,26 @@ func (t *TestTLSServer) CloneClient(clt *Client) *Client {
|
|||
return newClient
|
||||
}
|
||||
|
||||
// NewClientWithCert creates a new client using given cert and private key
|
||||
func (t *TestTLSServer) NewClientWithCert(clientCert tls.Certificate) *Client {
|
||||
tlsConfig, err := t.Identity.TLSConfig(t.AuthServer.CipherSuites)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tlsConfig.Time = t.AuthServer.AuthServer.clock.Now
|
||||
tlsConfig.Certificates = []tls.Certificate{clientCert}
|
||||
newClient, err := NewClient(client.Config{
|
||||
Addrs: []string{t.Addr().String()},
|
||||
Credentials: []client.Credentials{
|
||||
client.LoadTLS(tlsConfig),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return newClient
|
||||
}
|
||||
|
||||
// NewClient returns new client to test server authenticated with identity
|
||||
func (t *TestTLSServer) NewClient(identity TestIdentity) (*Client, error) {
|
||||
tlsConfig, err := t.ClientTLSConfig(identity)
|
||||
|
@ -736,6 +757,29 @@ func CreateUserRoleAndRequestable(clt clt, username string, rolename string) (se
|
|||
return user, nil
|
||||
}
|
||||
|
||||
// CreateUser creates user and role and assignes role to a user, used in tests
|
||||
func CreateUser(clt clt, username string, roles ...types.Role) (types.User, error) {
|
||||
ctx := context.TODO()
|
||||
user, err := services.NewUser(username)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
err = clt.UpsertRole(ctx, role)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
user.AddRole(role.GetName())
|
||||
}
|
||||
|
||||
err = clt.UpsertUser(user)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// CreateUserAndRole creates user and role and assignes role to a user, used in tests
|
||||
func CreateUserAndRole(clt clt, username string, allowedLogins []string) (services.User, services.Role, error) {
|
||||
ctx := context.TODO()
|
||||
|
|
|
@ -283,6 +283,9 @@ func (k *Keygen) GenerateUserCertWithoutValidation(c services.UserCertParams) ([
|
|||
if c.ClientIP != "" {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionClientIP] = c.ClientIP
|
||||
}
|
||||
if c.Impersonator != "" {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionImpersonator] = c.Impersonator
|
||||
}
|
||||
|
||||
// Add roles, traits, and route to cluster in the certificate extensions if
|
||||
// the standard format was requested. Certificate extensions are not included
|
||||
|
|
|
@ -155,7 +155,8 @@ func (a *Server) UpsertOIDCConnector(ctx context.Context, connector services.OID
|
|||
Code: events.OIDCConnectorCreatedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connector.GetName(),
|
||||
|
@ -178,7 +179,8 @@ func (a *Server) DeleteOIDCConnector(ctx context.Context, connectorName string)
|
|||
Code: events.OIDCConnectorDeletedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connectorName,
|
||||
|
|
|
@ -638,6 +638,18 @@ func clientUsername(ctx context.Context) string {
|
|||
return identity.Username
|
||||
}
|
||||
|
||||
// clientImpersonator returns the impersonator username of a remote client
|
||||
// making the call. If not present, returns an empty string
|
||||
func clientImpersonator(ctx context.Context) string {
|
||||
userI := ctx.Value(ContextUser)
|
||||
userWithIdentity, ok := userI.(IdentityGetter)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
identity := userWithIdentity.GetIdentity()
|
||||
return identity.Impersonator
|
||||
}
|
||||
|
||||
// LocalUser is a local user
|
||||
type LocalUser struct {
|
||||
// Username is local username
|
||||
|
|
|
@ -138,7 +138,8 @@ func (s *Server) CreateResetPasswordToken(ctx context.Context, req CreateResetPa
|
|||
Code: events.ResetPasswordTokenCreateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: req.Name,
|
||||
|
|
|
@ -46,7 +46,8 @@ func (a *Server) UpsertSAMLConnector(ctx context.Context, connector services.SAM
|
|||
Code: events.SAMLConnectorCreatedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connector.GetName(),
|
||||
|
@ -69,7 +70,8 @@ func (a *Server) DeleteSAMLConnector(ctx context.Context, connectorName string)
|
|||
Code: events.SAMLConnectorDeletedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: connectorName,
|
||||
|
|
|
@ -156,11 +156,13 @@ func (s *AuthSuite) GenerateUserCert(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
|
||||
inRoles := []string{"role-1", "role-2"}
|
||||
impersonator := "alice"
|
||||
cert, err = s.A.GenerateUserCert(services.UserCertParams{
|
||||
PrivateCASigningKey: priv,
|
||||
CASigningAlg: defaults.CASignatureAlgorithm,
|
||||
PublicUserKey: pub,
|
||||
Username: "user",
|
||||
Impersonator: impersonator,
|
||||
AllowedLogins: []string{"root"},
|
||||
TTL: time.Hour,
|
||||
PermitAgentForwarding: true,
|
||||
|
@ -174,6 +176,9 @@ func (s *AuthSuite) GenerateUserCert(c *check.C) {
|
|||
outRoles, err := services.UnmarshalCertRoles(parsedCert.Extensions[teleport.CertExtensionTeleportRoles])
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(outRoles, check.DeepEquals, inRoles)
|
||||
|
||||
outImpersonator := parsedCert.Extensions[teleport.CertExtensionImpersonator]
|
||||
c.Assert(outImpersonator, check.DeepEquals, impersonator)
|
||||
}
|
||||
|
||||
func checkCertExpiry(cert []byte, after, before time.Time) error {
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/tls"
|
||||
"encoding/base32"
|
||||
"encoding/json"
|
||||
|
@ -1860,22 +1861,24 @@ func TestGenerateCerts(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Contains(t, hostCert.ValidPrincipals, "example.com")
|
||||
|
||||
// attempt to elevate privileges by getting admin role in the certificate
|
||||
_, err = hostClient.GenerateServerKeys(
|
||||
GenerateServerKeysRequest{
|
||||
HostID: hostID,
|
||||
NodeName: srv.AuthServer.ClusterName,
|
||||
Roles: teleport.Roles{teleport.RoleAdmin},
|
||||
})
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
t.Run("HostClients", func(t *testing.T) {
|
||||
// attempt to elevate privileges by getting admin role in the certificate
|
||||
_, err = hostClient.GenerateServerKeys(
|
||||
GenerateServerKeysRequest{
|
||||
HostID: hostID,
|
||||
NodeName: srv.AuthServer.ClusterName,
|
||||
Roles: teleport.Roles{teleport.RoleAdmin},
|
||||
})
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
|
||||
// attempt to get certificate for different host id
|
||||
_, err = hostClient.GenerateServerKeys(GenerateServerKeysRequest{
|
||||
HostID: "some-other-host-id",
|
||||
NodeName: srv.AuthServer.ClusterName,
|
||||
Roles: teleport.Roles{teleport.RoleNode},
|
||||
// attempt to get certificate for different host id
|
||||
_, err = hostClient.GenerateServerKeys(GenerateServerKeysRequest{
|
||||
HostID: "some-other-host-id",
|
||||
NodeName: srv.AuthServer.ClusterName,
|
||||
Roles: teleport.Roles{teleport.RoleNode},
|
||||
})
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
})
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
|
||||
user1, userRole, err := CreateUserAndRole(srv.Auth(), "user1", []string{"user1"})
|
||||
require.NoError(t, err)
|
||||
|
@ -1883,52 +1886,37 @@ func TestGenerateCerts(t *testing.T) {
|
|||
user2, userRole2, err := CreateUserAndRole(srv.Auth(), "user2", []string{"user2"})
|
||||
require.NoError(t, err)
|
||||
|
||||
// unauthenticated client should NOT be able to generate a user cert without auth
|
||||
nopClient, err := srv.NewClient(TestNop())
|
||||
require.NoError(t, err)
|
||||
t.Run("Nop", func(t *testing.T) {
|
||||
// unauthenticated client should NOT be able to generate a user cert without auth
|
||||
nopClient, err := srv.NewClient(TestNop())
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = nopClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
_, err = nopClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.True(t, trace.IsAccessDenied(err), err.Error())
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
require.Contains(t, err.Error(), "this request can be only executed by an admin")
|
||||
|
||||
// User can't generate certificates for another user
|
||||
testUser2 := TestUser(user2.GetName())
|
||||
testUser2.TTL = time.Hour
|
||||
userClient2, err := srv.NewClient(testUser2)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
t.Run("ImpersonateDeny", func(t *testing.T) {
|
||||
// User can't generate certificates for another user by default
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
require.Contains(t, err.Error(), "this request can be only executed by an admin")
|
||||
|
||||
rc1, err := types.NewRemoteCluster("cluster1")
|
||||
require.NoError(t, err)
|
||||
err = srv.Auth().CreateRemoteCluster(rc1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// User can renew their certificates, however the TTL will be limited
|
||||
// to the TTL of their session for both SSH and x509 certs and
|
||||
// that route to cluster will be encoded in the cert metadata
|
||||
userCerts, err := userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc1.GetName(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
parseCert := func(sshCert []byte) (*ssh.Certificate, time.Duration) {
|
||||
parsedCert, err := sshutils.ParseCertificate(sshCert)
|
||||
|
@ -1936,120 +1924,266 @@ func TestGenerateCerts(t *testing.T) {
|
|||
validBefore := time.Unix(int64(parsedCert.ValidBefore), 0)
|
||||
return parsedCert, time.Until(validBefore)
|
||||
}
|
||||
_, diff := parseCert(userCerts.SSH)
|
||||
require.Less(t, int64(diff), int64(testUser2.TTL))
|
||||
|
||||
tlsCert, err := tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err := tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
require.True(t, identity.Expires.Before(time.Now().Add(testUser2.TTL)))
|
||||
require.Equal(t, identity.RouteToCluster, rc1.GetName())
|
||||
clock := srv.Auth().GetClock()
|
||||
t.Run("ImpersonateAllow", func(t *testing.T) {
|
||||
// Super impersonator impersonate anyone and login as root
|
||||
maxSessionTTL := 300 * time.Hour
|
||||
superImpersonatorRole, err := services.NewRole("superimpersonator", types.RoleSpecV3{
|
||||
Options: types.RoleOptions{
|
||||
MaxSessionTTL: types.Duration(maxSessionTTL),
|
||||
},
|
||||
Allow: types.RoleConditions{
|
||||
Logins: []string{"root"},
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{types.Wildcard},
|
||||
Roles: []string{types.Wildcard},
|
||||
},
|
||||
Rules: []types.Rule{},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
superImpersonator, err := CreateUser(srv.Auth(), "superimpersonator", superImpersonatorRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Admin should be allowed to generate certs with TTL longer than max.
|
||||
adminClient, err := srv.NewClient(TestAdmin())
|
||||
require.NoError(t, err)
|
||||
// Impersonator can generate certificates for super impersonator
|
||||
role, err := services.NewRole("impersonate", types.RoleSpecV3{
|
||||
Allow: types.RoleConditions{
|
||||
Logins: []string{superImpersonator.GetName()},
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{superImpersonator.GetName()},
|
||||
Roles: []string{superImpersonatorRole.GetName()},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
impersonator, err := CreateUser(srv.Auth(), "impersonator", role)
|
||||
require.NoError(t, err)
|
||||
|
||||
userCerts, err = adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(40 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
iUser := TestUser(impersonator.GetName())
|
||||
iUser.TTL = time.Hour
|
||||
iClient, err := srv.NewClient(iUser)
|
||||
require.NoError(t, err)
|
||||
|
||||
// can impersonate super impersonator and request certs
|
||||
// longer than their own TTL, but not exceeding super impersonator's max session ttl
|
||||
userCerts, err := iClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: superImpersonator.GetName(),
|
||||
Expires: clock.Now().Add(1000 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, diff := parseCert(userCerts.SSH)
|
||||
require.Less(t, int64(diff), int64(iUser.TTL))
|
||||
|
||||
tlsCert, err := tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err := tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Because the original request has maxed out the possible max
|
||||
// session TTL, it will be adjusted to exactly the value
|
||||
require.Equal(t, identity.Expires.Sub(clock.Now()), maxSessionTTL)
|
||||
require.Equal(t, impersonator.GetName(), identity.Impersonator)
|
||||
require.Equal(t, superImpersonator.GetName(), identity.Username)
|
||||
|
||||
// impersonator can't impersonate user1
|
||||
_, err = iClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: clock.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.IsType(t, &trace.AccessDeniedError{}, err)
|
||||
|
||||
_, privateKeyPEM, err := utils.MarshalPrivateKey(privateKey.(crypto.Signer))
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCert, err := tls.X509KeyPair(userCerts.TLS, privateKeyPEM)
|
||||
require.NoError(t, err)
|
||||
|
||||
// client that uses impersonated certificate can't impersonate other users
|
||||
// although super impersonator's roles allow it
|
||||
impersonatedClient := srv.NewClientWithCert(clientCert)
|
||||
_, err = impersonatedClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.IsType(t, &trace.AccessDeniedError{}, err)
|
||||
require.Contains(t, err.Error(), "impersonated user can not impersonate anyone else")
|
||||
|
||||
// but can renew their own cert, for example set route to cluster
|
||||
rc, err := types.NewRemoteCluster("cluster-remote")
|
||||
require.NoError(t, err)
|
||||
err = srv.Auth().CreateRemoteCluster(rc)
|
||||
require.NoError(t, err)
|
||||
|
||||
userCerts, err = impersonatedClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: superImpersonator.GetName(),
|
||||
Expires: clock.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc.GetName(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// Make sure impersonator was not lost in the renewed cert
|
||||
tlsCert, err = tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err = tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, identity.Expires.Sub(clock.Now()), time.Hour)
|
||||
require.Equal(t, impersonator.GetName(), identity.Impersonator)
|
||||
require.Equal(t, superImpersonator.GetName(), identity.Username)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
parsedCert, diff := parseCert(userCerts.SSH)
|
||||
require.Less(t, int64(defaults.MaxCertDuration), int64(diff))
|
||||
t.Run("Renew", func(t *testing.T) {
|
||||
testUser2 := TestUser(user2.GetName())
|
||||
testUser2.TTL = time.Hour
|
||||
userClient2, err := srv.NewClient(testUser2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// user should have agent forwarding (default setting)
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitAgentForwarding)
|
||||
rc1, err := types.NewRemoteCluster("cluster1")
|
||||
require.NoError(t, err)
|
||||
err = srv.Auth().CreateRemoteCluster(rc1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// user should not have X11 forwarding (default setting)
|
||||
require.NotContains(t, parsedCert.Extensions, teleport.CertExtensionPermitX11Forwarding)
|
||||
// User can renew their certificates, however the TTL will be limited
|
||||
// to the TTL of their session for both SSH and x509 certs and
|
||||
// that route to cluster will be encoded in the cert metadata
|
||||
userCerts, err := userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc1.GetName(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// now update role to permit agent and X11 forwarding
|
||||
roleOptions := userRole.GetOptions()
|
||||
roleOptions.ForwardAgent = services.NewBool(true)
|
||||
roleOptions.PermitX11Forwarding = services.NewBool(true)
|
||||
userRole.SetOptions(roleOptions)
|
||||
err = srv.Auth().UpsertRole(ctx, userRole)
|
||||
require.NoError(t, err)
|
||||
_, diff := parseCert(userCerts.SSH)
|
||||
require.Less(t, int64(diff), int64(testUser2.TTL))
|
||||
|
||||
userCerts, err = adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(1 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
tlsCert, err := tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err := tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
require.True(t, identity.Expires.Before(time.Now().Add(testUser2.TTL)))
|
||||
require.Equal(t, identity.RouteToCluster, rc1.GetName())
|
||||
})
|
||||
require.NoError(t, err)
|
||||
parsedCert, _ = parseCert(userCerts.SSH)
|
||||
|
||||
// user should get agent forwarding
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitAgentForwarding)
|
||||
t.Run("Admin", func(t *testing.T) {
|
||||
// Admin should be allowed to generate certs with TTL longer than max.
|
||||
adminClient, err := srv.NewClient(TestAdmin())
|
||||
require.NoError(t, err)
|
||||
|
||||
// user should get X11 forwarding
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitX11Forwarding)
|
||||
userCerts, err := adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(40 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// apply HTTP Auth to generate user cert:
|
||||
userCerts, err = adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
parsedCert, diff := parseCert(userCerts.SSH)
|
||||
require.Less(t, int64(defaults.MaxCertDuration), int64(diff))
|
||||
|
||||
// user should have agent forwarding (default setting)
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitAgentForwarding)
|
||||
|
||||
// user should not have X11 forwarding (default setting)
|
||||
require.NotContains(t, parsedCert.Extensions, teleport.CertExtensionPermitX11Forwarding)
|
||||
|
||||
// now update role to permit agent and X11 forwarding
|
||||
roleOptions := userRole.GetOptions()
|
||||
roleOptions.ForwardAgent = services.NewBool(true)
|
||||
roleOptions.PermitX11Forwarding = services.NewBool(true)
|
||||
userRole.SetOptions(roleOptions)
|
||||
err = srv.Auth().UpsertRole(ctx, userRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
userCerts, err = adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(1 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
parsedCert, _ = parseCert(userCerts.SSH)
|
||||
|
||||
// user should get agent forwarding
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitAgentForwarding)
|
||||
|
||||
// user should get X11 forwarding
|
||||
require.Contains(t, parsedCert.Extensions, teleport.CertExtensionPermitX11Forwarding)
|
||||
|
||||
// apply HTTP Auth to generate user cert:
|
||||
userCerts, err = adminClient.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user1.GetName(),
|
||||
Expires: time.Now().Add(time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, _, _, err = ssh.ParseAuthorizedKey(userCerts.SSH)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, _, _, err = ssh.ParseAuthorizedKey(userCerts.SSH)
|
||||
require.NoError(t, err)
|
||||
t.Run("DenyLeaf", func(t *testing.T) {
|
||||
// User can't generate certificates for an unknown leaf cluster.
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: "unknown_cluster",
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
// User can't generate certificates for an unknown leaf cluster.
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: "unknown_cluster",
|
||||
rc2, err := types.NewRemoteCluster("cluster2")
|
||||
require.NoError(t, err)
|
||||
meta := rc2.GetMetadata()
|
||||
meta.Labels = map[string]string{"env": "prod"}
|
||||
rc2.SetMetadata(meta)
|
||||
err = srv.Auth().CreateRemoteCluster(rc2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// User can't generate certificates for leaf cluster they don't have access
|
||||
// to due to labels.
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc2.GetName(),
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
userRole2.SetClusterLabels(types.Allow, types.Labels{"env": utils.Strings{"prod"}})
|
||||
err = srv.Auth().UpsertRole(ctx, userRole2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// User can generate certificates for leaf cluster they do have access to.
|
||||
userCerts, err := userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc2.GetName(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tlsCert, err := tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err := tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, identity.RouteToCluster, rc2.GetName())
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
rc2, err := types.NewRemoteCluster("cluster2")
|
||||
require.NoError(t, err)
|
||||
meta := rc2.GetMetadata()
|
||||
meta.Labels = map[string]string{"env": "prod"}
|
||||
rc2.SetMetadata(meta)
|
||||
err = srv.Auth().CreateRemoteCluster(rc2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// User can't generate certificates for leaf cluster they don't have access
|
||||
// to due to labels.
|
||||
_, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc2.GetName(),
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
userRole2.SetClusterLabels(types.Allow, types.Labels{"env": utils.Strings{"prod"}})
|
||||
err = srv.Auth().UpsertRole(ctx, userRole2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// User can generate certificates for leaf cluster they do have access to.
|
||||
userCerts, err = userClient2.GenerateUserCerts(ctx, proto.UserCertsRequest{
|
||||
PublicKey: pub,
|
||||
Username: user2.GetName(),
|
||||
Expires: time.Now().Add(100 * time.Hour).UTC(),
|
||||
Format: teleport.CertificateFormatStandard,
|
||||
RouteToCluster: rc2.GetName(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tlsCert, err = tlsca.ParseCertificatePEM(userCerts.TLS)
|
||||
require.NoError(t, err)
|
||||
identity, err = tlsca.FromSubject(tlsCert.Subject, tlsCert.NotAfter)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, identity.RouteToCluster, rc2.GetName())
|
||||
}
|
||||
|
||||
// TestGenerateAppToken checks the identity of the caller and makes sure only
|
||||
|
|
|
@ -147,7 +147,8 @@ func (a *Server) UpsertTrustedCluster(ctx context.Context, trustedCluster servic
|
|||
Code: events.TrustedClusterCreateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: trustedCluster.GetName(),
|
||||
|
@ -220,7 +221,8 @@ func (a *Server) DeleteTrustedCluster(ctx context.Context, name string) error {
|
|||
Code: events.TrustedClusterDeleteCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: name,
|
||||
|
|
|
@ -62,7 +62,8 @@ func (s *Server) CreateUser(ctx context.Context, user services.User) error {
|
|||
Code: events.UserCreateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: user.GetCreatedBy().User.Name,
|
||||
User: user.GetCreatedBy().User.Name,
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: user.GetName(),
|
||||
|
@ -96,7 +97,8 @@ func (s *Server) UpdateUser(ctx context.Context, user services.User) error {
|
|||
Code: events.UserUpdateCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: user.GetName(),
|
||||
|
@ -173,7 +175,8 @@ func (s *Server) DeleteUser(ctx context.Context, user string) error {
|
|||
Code: events.UserDeleteCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: clientUsername(ctx),
|
||||
User: clientUsername(ctx),
|
||||
Impersonator: clientImpersonator(ctx),
|
||||
},
|
||||
ResourceMetadata: events.ResourceMetadata{
|
||||
Name: user,
|
||||
|
|
|
@ -734,8 +734,9 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ
|
|||
WithMFA: ctx.Identity.GetIdentity().MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
TerminalSize: params.Serialize(),
|
||||
KubernetesClusterMetadata: ctx.eventClusterMeta(),
|
||||
|
@ -776,8 +777,9 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ
|
|||
WithMFA: ctx.Identity.GetIdentity().MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
|
@ -859,8 +861,9 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ
|
|||
WithMFA: ctx.Identity.GetIdentity().MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
|
@ -890,8 +893,9 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ
|
|||
WithMFA: ctx.Identity.GetIdentity().MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
|
@ -926,8 +930,9 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ
|
|||
WithMFA: ctx.Identity.GetIdentity().MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
|
@ -989,8 +994,9 @@ func (f *Forwarder) portForward(ctx *authContext, w http.ResponseWriter, req *ht
|
|||
Code: events.PortForwardCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: sess.teleportCluster.targetAddr,
|
||||
|
@ -1179,8 +1185,9 @@ func (f *Forwarder) catchAll(ctx *authContext, w http.ResponseWriter, req *http.
|
|||
Code: events.KubeRequestCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
User: ctx.User.GetName(),
|
||||
Login: ctx.User.GetName(),
|
||||
Impersonator: ctx.Identity.GetIdentity().Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
|
|
|
@ -245,6 +245,8 @@ type UserCertParams struct {
|
|||
TTL time.Duration
|
||||
// Username is teleport username
|
||||
Username string
|
||||
// Impersonator is set when a user requests certificate for another user
|
||||
Impersonator string
|
||||
// AllowedLogins is a list of SSH principals
|
||||
AllowedLogins []string
|
||||
// PermitX11Forwarding permits X11 forwarding for this cert
|
||||
|
|
85
lib/services/impersonate.go
Normal file
85
lib/services/impersonate.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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 services
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/vulcand/predicate"
|
||||
)
|
||||
|
||||
// impersonateContext is a default rule context used in teleport
|
||||
type impersonateContext struct {
|
||||
// user is currently authenticated user
|
||||
user types.User
|
||||
// impersonateRole is a role to impersonate
|
||||
impersonateRole types.Role
|
||||
// impersonateUser is a user to impersonate
|
||||
impersonateUser types.User
|
||||
}
|
||||
|
||||
// getIdentifier returns identifier defined in a context
|
||||
func (ctx *impersonateContext) getIdentifier(fields []string) (interface{}, error) {
|
||||
switch fields[0] {
|
||||
case UserIdentifier:
|
||||
return predicate.GetFieldByTag(ctx.user, teleport.JSON, fields[1:])
|
||||
case ImpersonateUserIdentifier:
|
||||
return predicate.GetFieldByTag(ctx.impersonateUser, teleport.JSON, fields[1:])
|
||||
case ImpersonateRoleIdentifier:
|
||||
return predicate.GetFieldByTag(ctx.impersonateRole, teleport.JSON, fields[1:])
|
||||
default:
|
||||
return nil, trace.NotFound("%v is not defined", strings.Join(fields, "."))
|
||||
}
|
||||
}
|
||||
|
||||
// matchesImpersonateWhere returns true if Where rule matches.
|
||||
// Empty Where block always matches.
|
||||
func matchesImpersonateWhere(cond types.ImpersonateConditions, parser predicate.Parser) (bool, error) {
|
||||
if cond.Where == "" {
|
||||
return true, nil
|
||||
}
|
||||
ifn, err := parser.Parse(cond.Where)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
fn, ok := ifn.(predicate.BoolPredicate)
|
||||
if !ok {
|
||||
return false, trace.BadParameter("invalid predicate type for where expression: %v", cond.Where)
|
||||
}
|
||||
return fn(), nil
|
||||
}
|
||||
|
||||
// newImpersonateWhereParser returns standard parser for `where` section in impersonate rules
|
||||
func newImpersonateWhereParser(ctx *impersonateContext) (predicate.Parser, error) {
|
||||
return predicate.NewParser(predicate.Def{
|
||||
Operators: predicate.Operators{
|
||||
AND: predicate.And,
|
||||
OR: predicate.Or,
|
||||
NOT: predicate.Not,
|
||||
},
|
||||
Functions: map[string]interface{}{
|
||||
"equals": predicate.Equals,
|
||||
"contains": predicate.Contains,
|
||||
},
|
||||
GetIdentifier: ctx.getIdentifier,
|
||||
GetProperty: GetStringMapValue,
|
||||
})
|
||||
}
|
272
lib/services/impersonate_test.go
Normal file
272
lib/services/impersonate_test.go
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
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 services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCheckImpersonate(t *testing.T) {
|
||||
noLabelsRole := &types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "no-labels",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: types.RoleSpecV3{
|
||||
Allow: types.RoleConditions{
|
||||
Namespaces: []string{defaults.Namespace},
|
||||
},
|
||||
},
|
||||
}
|
||||
wildcardRole := &types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "wildcard",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: types.RoleSpecV3{
|
||||
Allow: types.RoleConditions{
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{types.Wildcard},
|
||||
Roles: []string{types.Wildcard},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
wildcardDenyRole := &types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "wildcard-deny-user",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: types.RoleSpecV3{
|
||||
Deny: types.RoleConditions{
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{types.Wildcard},
|
||||
Roles: []string{types.Wildcard},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
type props struct {
|
||||
traits map[string][]string
|
||||
labels map[string]string
|
||||
}
|
||||
var empty props
|
||||
newUser := func(name string, props props) types.User {
|
||||
u := &UserV2{
|
||||
Kind: types.KindUser,
|
||||
Version: types.V2,
|
||||
Metadata: types.Metadata{
|
||||
Name: name,
|
||||
Namespace: defaults.Namespace,
|
||||
Labels: props.labels,
|
||||
},
|
||||
Spec: types.UserSpecV2{
|
||||
Traits: props.traits,
|
||||
},
|
||||
}
|
||||
if err := u.CheckAndSetDefaults(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
type impersonate struct {
|
||||
name string
|
||||
allowed bool
|
||||
user types.User
|
||||
roles []types.Role
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
user types.User
|
||||
roles []types.Role
|
||||
checks []impersonate
|
||||
}{
|
||||
{
|
||||
name: "empty role set can impersonate no other user",
|
||||
user: newUser("alice", empty),
|
||||
checks: []impersonate{
|
||||
{
|
||||
allowed: false,
|
||||
user: newUser("bob", empty),
|
||||
roles: []types.Role{
|
||||
noLabelsRole,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wildcard role can impersonate any user or role",
|
||||
user: newUser("alice", empty),
|
||||
roles: []types.Role{
|
||||
wildcardRole,
|
||||
},
|
||||
checks: []impersonate{
|
||||
{
|
||||
allowed: true,
|
||||
user: newUser("bob", empty),
|
||||
roles: []types.Role{
|
||||
noLabelsRole,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wildcard deny user overrides wildcard allow",
|
||||
user: newUser("alice", empty),
|
||||
roles: []types.Role{
|
||||
wildcardRole,
|
||||
wildcardDenyRole,
|
||||
},
|
||||
checks: []impersonate{
|
||||
{
|
||||
allowed: false,
|
||||
user: newUser("bob", empty),
|
||||
roles: []types.Role{
|
||||
noLabelsRole,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "impersonate condition is limited to a certain set users and roles",
|
||||
user: newUser("alice", empty),
|
||||
roles: []types.Role{
|
||||
&types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "limited",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: types.RoleSpecV3{
|
||||
Allow: types.RoleConditions{
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{"bob"},
|
||||
Roles: []string{noLabelsRole.GetName()},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
checks: []impersonate{
|
||||
{
|
||||
allowed: true,
|
||||
user: newUser("bob", empty),
|
||||
roles: []types.Role{
|
||||
noLabelsRole,
|
||||
},
|
||||
},
|
||||
{
|
||||
allowed: false,
|
||||
user: newUser("alice", empty),
|
||||
roles: []types.Role{
|
||||
noLabelsRole,
|
||||
},
|
||||
},
|
||||
{
|
||||
allowed: false,
|
||||
user: newUser("bob", empty),
|
||||
roles: []types.Role{
|
||||
wildcardRole,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Alice can impersonate any user and role from dev team",
|
||||
user: newUser("alice", props{traits: map[string][]string{"team": []string{"dev"}}}),
|
||||
roles: []types.Role{
|
||||
&types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "team-impersonator",
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: types.RoleSpecV3{
|
||||
Allow: types.RoleConditions{
|
||||
Impersonate: &types.ImpersonateConditions{
|
||||
Users: []string{Wildcard},
|
||||
Roles: []string{Wildcard},
|
||||
Where: `equals(user.spec.traits["team"], impersonate_user.spec.traits["team"]) && contains(user.spec.traits["team"], impersonate_role.metadata.labels["team"])`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
checks: []impersonate{
|
||||
{
|
||||
allowed: true,
|
||||
user: newUser("bob", props{
|
||||
traits: map[string][]string{"team": []string{"dev"}},
|
||||
}),
|
||||
roles: []types.Role{
|
||||
&types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "dev",
|
||||
Namespace: defaults.Namespace,
|
||||
Labels: map[string]string{
|
||||
"team": "dev",
|
||||
},
|
||||
},
|
||||
Spec: types.RoleSpecV3{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all roles in the set have to match where condition",
|
||||
allowed: false,
|
||||
user: newUser("bob", props{
|
||||
traits: map[string][]string{"team": []string{"dev"}},
|
||||
}),
|
||||
roles: []types.Role{
|
||||
wildcardRole,
|
||||
&types.RoleV3{
|
||||
Metadata: types.Metadata{
|
||||
Name: "dev",
|
||||
Namespace: defaults.Namespace,
|
||||
Labels: map[string]string{
|
||||
"team": "dev",
|
||||
},
|
||||
},
|
||||
Spec: types.RoleSpecV3{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
var set RoleSet
|
||||
for i := range tc.roles {
|
||||
set = append(set, tc.roles[i])
|
||||
}
|
||||
for j, impersonate := range tc.checks {
|
||||
comment := fmt.Sprintf("test case %v '%v', check %v %v", i, tc.name, j, impersonate.name)
|
||||
result := set.CheckImpersonate(tc.user, impersonate.user, impersonate.roles)
|
||||
if impersonate.allowed {
|
||||
require.NoError(t, result, comment)
|
||||
} else {
|
||||
require.True(t, trace.IsAccessDenied(result), fmt.Sprintf("%v: %v", comment, result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -188,6 +188,10 @@ const (
|
|||
UserIdentifier = "user"
|
||||
// ResourceIdentifier represents resource registered identifier in the rules
|
||||
ResourceIdentifier = "resource"
|
||||
// ImpersonateRoleIdentifier is a role to impersonate
|
||||
ImpersonateRoleIdentifier = "impersonate_role"
|
||||
// ImpersonateUserIdentifier is a user to impersonate
|
||||
ImpersonateUserIdentifier = "impersonate_user"
|
||||
)
|
||||
|
||||
// GetResource returns resource specified in the context,
|
||||
|
|
|
@ -54,6 +54,7 @@ func NewPresetEditorRole() Role {
|
|||
NewRule(KindClusterConfig, RW()),
|
||||
NewRule(KindTrustedCluster, RW()),
|
||||
NewRule(KindRemoteCluster, RW()),
|
||||
NewRule(KindToken, RW()),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -509,6 +509,34 @@ func ApplyTraits(r Role, traits map[string][]string) Role {
|
|||
if inLabels != nil {
|
||||
r.SetDatabaseLabels(condition, applyLabelsTraits(inLabels, traits))
|
||||
}
|
||||
|
||||
// apply templates to impersonation conditions
|
||||
inCond := r.GetImpersonateConditions(condition)
|
||||
var outCond types.ImpersonateConditions
|
||||
for _, user := range inCond.Users {
|
||||
variableValues, err := applyValueTraits(user, traits)
|
||||
if err != nil {
|
||||
if !trace.IsNotFound(err) {
|
||||
log.WithError(err).Debugf("Skipping impersonate user %q.", user)
|
||||
}
|
||||
continue
|
||||
}
|
||||
outCond.Users = append(outCond.Users, variableValues...)
|
||||
}
|
||||
for _, role := range inCond.Roles {
|
||||
variableValues, err := applyValueTraits(role, traits)
|
||||
if err != nil {
|
||||
if !trace.IsNotFound(err) {
|
||||
log.WithError(err).Debugf("Skipping impersonate role %q.", role)
|
||||
}
|
||||
continue
|
||||
}
|
||||
outCond.Roles = append(outCond.Roles, variableValues...)
|
||||
}
|
||||
outCond.Users = utils.Deduplicate(outCond.Users)
|
||||
outCond.Roles = utils.Deduplicate(outCond.Roles)
|
||||
outCond.Where = inCond.Where
|
||||
r.SetImpersonateConditions(condition, outCond)
|
||||
}
|
||||
|
||||
return r
|
||||
|
@ -811,9 +839,17 @@ type AccessChecker interface {
|
|||
// CheckDatabaseNamesAndUsers returns database names and users this role
|
||||
// is allowed to use.
|
||||
CheckDatabaseNamesAndUsers(ttl time.Duration, overrideTTL bool) (names []string, users []string, err error)
|
||||
|
||||
// CheckAccessToDatabase checks whether a user has access to the provided
|
||||
// database server.
|
||||
CheckAccessToDatabase(server types.DatabaseServer, mfa AccessMFAParams, matchers ...RoleMatcher) error
|
||||
|
||||
// CheckImpersonate checks whether current user is allowed to impersonate
|
||||
// users and roles
|
||||
CheckImpersonate(currentUser, impersonateUser types.User, impersonateRoles []types.Role) error
|
||||
|
||||
// CanImpersonateSomeone returns true if this checker has any impersonation rules
|
||||
CanImpersonateSomeone() bool
|
||||
}
|
||||
|
||||
// FromSpec returns new RoleSet created from spec
|
||||
|
@ -900,10 +936,9 @@ func ExtractFromIdentity(access UserGetter, identity tlsca.Identity) ([]string,
|
|||
return identity.Groups, identity.Traits, nil
|
||||
}
|
||||
|
||||
// FetchRoles fetches roles by their names, applies the traits to role
|
||||
// variables, and returns the RoleSet. Adds runtime roles like the default
|
||||
// implicit role to RoleSet.
|
||||
func FetchRoles(roleNames []string, access RoleGetter, traits map[string][]string) (RoleSet, error) {
|
||||
// FetchRoleList fetches roles by their names, applies the traits to role
|
||||
// variables, and returns the list
|
||||
func FetchRoleList(roleNames []string, access RoleGetter, traits map[string][]string) (RoleSet, error) {
|
||||
var roles []Role
|
||||
|
||||
for _, roleName := range roleNames {
|
||||
|
@ -914,6 +949,17 @@ func FetchRoles(roleNames []string, access RoleGetter, traits map[string][]strin
|
|||
roles = append(roles, ApplyTraits(role, traits))
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// FetchRoles fetches roles by their names, applies the traits to role
|
||||
// variables, and returns the RoleSet. Adds runtime roles like the default
|
||||
// implicit role to RoleSet.
|
||||
func FetchRoles(roleNames []string, access RoleGetter, traits map[string][]string) (RoleSet, error) {
|
||||
roles, err := FetchRoleList(roleNames, access, traits)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return NewRoleSet(roles...), nil
|
||||
}
|
||||
|
||||
|
@ -1580,6 +1626,148 @@ func (set RoleSet) CheckAccessToKubernetes(namespace string, kube *KubernetesClu
|
|||
return trace.AccessDenied("access to kubernetes cluster denied")
|
||||
}
|
||||
|
||||
// CanImpersonateSomeone returns true if this checker has any impersonation rules
|
||||
func (set RoleSet) CanImpersonateSomeone() bool {
|
||||
for _, role := range set {
|
||||
cond := role.GetImpersonateConditions(Allow)
|
||||
if !cond.IsEmpty() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckImpersonate returns nil if this role set can impersonate
|
||||
// a user and their roles, returns AccessDenied otherwise
|
||||
// CheckImpersonate checks whether current user is allowed to impersonate
|
||||
// users and roles
|
||||
func (set RoleSet) CheckImpersonate(currentUser, impersonateUser types.User, impersonateRoles []types.Role) error {
|
||||
ctx := &impersonateContext{
|
||||
user: currentUser,
|
||||
impersonateUser: impersonateUser,
|
||||
}
|
||||
whereParser, err := newImpersonateWhereParser(ctx)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
// check deny: a single match on a deny rule prohibits access
|
||||
for _, role := range set {
|
||||
cond := role.GetImpersonateConditions(Deny)
|
||||
matched, err := matchDenyImpersonateCondition(cond, impersonateUser, impersonateRoles)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if matched {
|
||||
return trace.AccessDenied("access denied to '%s' to impersonate user '%s' and roles '%s'", currentUser.GetName(), impersonateUser.GetName(), roleNames(impersonateRoles))
|
||||
}
|
||||
}
|
||||
|
||||
// check allow: if matches, allow to impersonate
|
||||
for _, role := range set {
|
||||
cond := role.GetImpersonateConditions(Allow)
|
||||
matched, err := matchAllowImpersonateCondition(ctx, whereParser, cond, impersonateUser, impersonateRoles)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if matched {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return trace.AccessDenied("access denied to '%s' to impersonate user '%s' and roles '%s'", currentUser.GetName(), impersonateUser.GetName(), roleNames(impersonateRoles))
|
||||
}
|
||||
|
||||
func roleNames(roles []types.Role) string {
|
||||
out := make([]string, len(roles))
|
||||
for i := range roles {
|
||||
out[i] = roles[i].GetName()
|
||||
}
|
||||
return strings.Join(out, ", ")
|
||||
}
|
||||
|
||||
// matchAllowImpersonateCondition matches impersonate condition,
|
||||
// both user, role and where condition has to match
|
||||
func matchAllowImpersonateCondition(ctx *impersonateContext, whereParser predicate.Parser, cond types.ImpersonateConditions, impersonateUser types.User, impersonateRoles []types.Role) (bool, error) {
|
||||
// an empty set matches nothing
|
||||
if len(cond.Users) == 0 && len(cond.Roles) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
// should specify both roles and users, this condition is also verified on the role level
|
||||
if len(cond.Users) == 0 || len(cond.Roles) == 0 {
|
||||
return false, trace.BadParameter("the system does not support empty roles and users")
|
||||
}
|
||||
|
||||
anyUser, err := parse.NewAnyMatcher(cond.Users)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
|
||||
if !anyUser.Match(impersonateUser.GetName()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
anyRole, err := parse.NewAnyMatcher(cond.Roles)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
|
||||
for _, impersonateRole := range impersonateRoles {
|
||||
if !anyRole.Match(impersonateRole.GetName()) {
|
||||
return false, nil
|
||||
}
|
||||
// TODO:
|
||||
// This set impersonateRole inside the ctx that is in turn used inside whereParser
|
||||
// which is created in CheckImpersonate above but is being used right below.
|
||||
// This is unfortunate interface of the parser, instead
|
||||
// parser should accept additional context as a first argument.
|
||||
ctx.impersonateRole = impersonateRole
|
||||
match, err := matchesImpersonateWhere(cond, whereParser)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
if !match {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// matchDenyImpersonateCondition matches impersonate condition,
|
||||
// greedy is used for deny type rules, where any user or role can match
|
||||
func matchDenyImpersonateCondition(cond types.ImpersonateConditions, impersonateUser types.User, impersonateRoles []types.Role) (bool, error) {
|
||||
// an empty set matches nothing
|
||||
if len(cond.Users) == 0 && len(cond.Roles) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
// should specify both roles and users, this condition is also verified on the role level
|
||||
if len(cond.Users) == 0 || len(cond.Roles) == 0 {
|
||||
return false, trace.BadParameter("the system does not support empty roles and users")
|
||||
}
|
||||
|
||||
anyUser, err := parse.NewAnyMatcher(cond.Users)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
|
||||
if anyUser.Match(impersonateUser.GetName()) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
anyRole, err := parse.NewAnyMatcher(cond.Roles)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err)
|
||||
}
|
||||
|
||||
for _, impersonateRole := range impersonateRoles {
|
||||
if anyRole.Match(impersonateRole.GetName()) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// RoleMatcher defines an interface for a generic role matcher.
|
||||
type RoleMatcher interface {
|
||||
Match(Role, RoleConditionType) (bool, error)
|
||||
|
@ -2029,6 +2217,23 @@ const RoleSpecV3SchemaDefinitions = `
|
|||
}
|
||||
}
|
||||
},
|
||||
"impersonate": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"users": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"where": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2015-2020 Gravitational, Inc.
|
||||
Copyright 2015-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.
|
||||
|
@ -1500,24 +1500,26 @@ func TestCheckRuleSorting(t *testing.T) {
|
|||
|
||||
func TestApplyTraits(t *testing.T) {
|
||||
type rule struct {
|
||||
inLogins []string
|
||||
outLogins []string
|
||||
inLabels Labels
|
||||
outLabels Labels
|
||||
inKubeLabels Labels
|
||||
outKubeLabels Labels
|
||||
inKubeGroups []string
|
||||
outKubeGroups []string
|
||||
inKubeUsers []string
|
||||
outKubeUsers []string
|
||||
inAppLabels Labels
|
||||
outAppLabels Labels
|
||||
inDBLabels Labels
|
||||
outDBLabels Labels
|
||||
inDBNames []string
|
||||
outDBNames []string
|
||||
inDBUsers []string
|
||||
outDBUsers []string
|
||||
inLogins []string
|
||||
outLogins []string
|
||||
inLabels Labels
|
||||
outLabels Labels
|
||||
inKubeLabels Labels
|
||||
outKubeLabels Labels
|
||||
inKubeGroups []string
|
||||
outKubeGroups []string
|
||||
inKubeUsers []string
|
||||
outKubeUsers []string
|
||||
inAppLabels Labels
|
||||
outAppLabels Labels
|
||||
inDBLabels Labels
|
||||
outDBLabels Labels
|
||||
inDBNames []string
|
||||
outDBNames []string
|
||||
inDBUsers []string
|
||||
outDBUsers []string
|
||||
inImpersonate types.ImpersonateConditions
|
||||
outImpersonate types.ImpersonateConditions
|
||||
}
|
||||
var tests = []struct {
|
||||
comment string
|
||||
|
@ -1818,6 +1820,38 @@ func TestApplyTraits(t *testing.T) {
|
|||
outDBLabels: Labels{`key`: []string{"bar", "baz"}},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
comment: "impersonate roles",
|
||||
inTraits: map[string][]string{
|
||||
"teams": {"devs"},
|
||||
"users": {"alice", "bob"},
|
||||
"blocked_users": {"root"},
|
||||
"blocked_teams": {"admins"},
|
||||
},
|
||||
allow: rule{
|
||||
inImpersonate: types.ImpersonateConditions{
|
||||
Users: []string{"{{external.users}}"},
|
||||
Roles: []string{"{{external.teams}}"},
|
||||
Where: `contains(user.spec.traits, "hello")`,
|
||||
},
|
||||
outImpersonate: types.ImpersonateConditions{
|
||||
Users: []string{"alice", "bob"},
|
||||
Roles: []string{"devs"},
|
||||
Where: `contains(user.spec.traits, "hello")`,
|
||||
},
|
||||
},
|
||||
deny: rule{
|
||||
inImpersonate: types.ImpersonateConditions{
|
||||
Users: []string{"{{external.blocked_users}}"},
|
||||
Roles: []string{"{{external.blocked_teams}}"},
|
||||
},
|
||||
outImpersonate: types.ImpersonateConditions{
|
||||
Users: []string{"root"},
|
||||
Roles: []string{"admins"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
|
@ -1842,6 +1876,7 @@ func TestApplyTraits(t *testing.T) {
|
|||
DatabaseLabels: tt.allow.inDBLabels,
|
||||
DatabaseNames: tt.allow.inDBNames,
|
||||
DatabaseUsers: tt.allow.inDBUsers,
|
||||
Impersonate: &tt.allow.inImpersonate,
|
||||
},
|
||||
Deny: RoleConditions{
|
||||
Logins: tt.deny.inLogins,
|
||||
|
@ -1854,6 +1889,7 @@ func TestApplyTraits(t *testing.T) {
|
|||
DatabaseLabels: tt.deny.inDBLabels,
|
||||
DatabaseNames: tt.deny.inDBNames,
|
||||
DatabaseUsers: tt.deny.inDBUsers,
|
||||
Impersonate: &tt.deny.inImpersonate,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1869,6 +1905,7 @@ func TestApplyTraits(t *testing.T) {
|
|||
require.Equal(t, outRole.GetDatabaseLabels(Allow), tt.allow.outDBLabels, comment)
|
||||
require.Equal(t, outRole.GetDatabaseNames(Allow), tt.allow.outDBNames, comment)
|
||||
require.Equal(t, outRole.GetDatabaseUsers(Allow), tt.allow.outDBUsers, comment)
|
||||
require.Equal(t, outRole.GetImpersonateConditions(Allow), tt.allow.outImpersonate, comment)
|
||||
|
||||
require.Equal(t, outRole.GetLogins(Deny), tt.deny.outLogins, comment)
|
||||
require.Equal(t, outRole.GetNodeLabels(Deny), tt.deny.outLabels, comment)
|
||||
|
@ -1880,6 +1917,7 @@ func TestApplyTraits(t *testing.T) {
|
|||
require.Equal(t, outRole.GetDatabaseLabels(Deny), tt.deny.outDBLabels, comment)
|
||||
require.Equal(t, outRole.GetDatabaseNames(Deny), tt.deny.outDBNames, comment)
|
||||
require.Equal(t, outRole.GetDatabaseUsers(Deny), tt.deny.outDBUsers, comment)
|
||||
require.Equal(t, outRole.GetImpersonateConditions(Deny), tt.deny.outImpersonate, comment)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,8 @@ func (s *Server) newStreamWriter(identity *tlsca.Identity) (events.StreamWriter,
|
|||
WithMFA: identity.MFAVerified,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: identity.Username,
|
||||
User: identity.Username,
|
||||
Impersonator: identity.Impersonator,
|
||||
},
|
||||
SessionChunkID: chunkID,
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ func (h *AuthHandlers) CreateIdentityContext(sconn *ssh.ServerConn) (IdentityCon
|
|||
return IdentityContext{}, trace.Wrap(err)
|
||||
}
|
||||
identity.RoleSet = roleSet
|
||||
identity.Impersonator = certificate.Extensions[teleport.CertExtensionImpersonator]
|
||||
|
||||
return identity, nil
|
||||
}
|
||||
|
@ -123,8 +124,9 @@ func (h *AuthHandlers) CheckPortForward(addr string, ctx *ServerContext) error {
|
|||
Code: events.PortForwardFailureCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: ctx.ServerConn.LocalAddr().String(),
|
||||
|
|
|
@ -132,6 +132,9 @@ type IdentityContext struct {
|
|||
// TeleportUser is the Teleport user associated with the connection.
|
||||
TeleportUser string
|
||||
|
||||
// Impersonator is a user acting on behalf of other user
|
||||
Impersonator string
|
||||
|
||||
// Login is the operating system user associated with the connection.
|
||||
Login string
|
||||
|
||||
|
@ -569,8 +572,9 @@ func (c *ServerContext) reportStats(conn utils.Stater) {
|
|||
WithMFA: c.Identity.Certificate.Extensions[teleport.CertExtensionMFAVerified],
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: c.Identity.TeleportUser,
|
||||
Login: c.Identity.Login,
|
||||
User: c.Identity.TeleportUser,
|
||||
Login: c.Identity.Login,
|
||||
Impersonator: c.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: c.ServerConn.RemoteAddr().String(),
|
||||
|
|
|
@ -69,7 +69,8 @@ func (a *Audit) OnSessionStart(ctx context.Context, session Session, sessionErr
|
|||
ServerNamespace: defaults.Namespace,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: session.Identity.Username,
|
||||
User: session.Identity.Username,
|
||||
Impersonator: session.Identity.Impersonator,
|
||||
},
|
||||
SessionMetadata: events.SessionMetadata{
|
||||
SessionID: session.ID,
|
||||
|
@ -112,7 +113,8 @@ func (a *Audit) OnSessionEnd(ctx context.Context, session Session) error {
|
|||
ClusterName: session.ClusterName,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: session.Identity.Username,
|
||||
User: session.Identity.Username,
|
||||
Impersonator: session.Identity.Impersonator,
|
||||
},
|
||||
SessionMetadata: events.SessionMetadata{
|
||||
SessionID: session.ID,
|
||||
|
@ -141,7 +143,8 @@ func (a *Audit) OnQuery(ctx context.Context, session Session, query string) erro
|
|||
ClusterName: session.ClusterName,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: session.Identity.Username,
|
||||
User: session.Identity.Username,
|
||||
Impersonator: session.Identity.Impersonator,
|
||||
},
|
||||
SessionMetadata: events.SessionMetadata{
|
||||
SessionID: session.ID,
|
||||
|
|
|
@ -372,8 +372,9 @@ func emitExecAuditEvent(ctx *ServerContext, cmd string, execErr error) {
|
|||
}
|
||||
|
||||
userMeta := events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
}
|
||||
|
||||
connectionMeta := events.ConnectionMetadata{
|
||||
|
|
|
@ -712,8 +712,9 @@ func (s *Server) handleDirectTCPIPRequest(ctx context.Context, ch ssh.Channel, r
|
|||
Code: events.PortForwardCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: s.identityContext.Login,
|
||||
User: s.identityContext.TeleportUser,
|
||||
Login: s.identityContext.Login,
|
||||
User: s.identityContext.TeleportUser,
|
||||
Impersonator: s.identityContext.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: s.sconn.LocalAddr().String(),
|
||||
|
@ -1049,8 +1050,9 @@ func (s *Server) handleX11Forward(ctx context.Context, ch ssh.Channel, req *ssh.
|
|||
Type: events.X11ForwardEvent,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: s.identityContext.Login,
|
||||
User: s.identityContext.TeleportUser,
|
||||
Login: s.identityContext.Login,
|
||||
User: s.identityContext.TeleportUser,
|
||||
Impersonator: s.identityContext.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: s.sconn.LocalAddr().String(),
|
||||
|
|
|
@ -136,8 +136,9 @@ func (r *remoteSubsystem) emitAuditEvent(err error) {
|
|||
Type: events.SubsystemEvent,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: r.serverContext.Identity.TeleportUser,
|
||||
Login: r.serverContext.Identity.Login,
|
||||
User: r.serverContext.Identity.TeleportUser,
|
||||
Login: r.serverContext.Identity.Login,
|
||||
Impersonator: r.serverContext.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: r.serverContext.RemoteClient.LocalAddr().String(),
|
||||
|
|
|
@ -886,8 +886,9 @@ func (s *Server) HandleNewConn(ctx context.Context, ccx *sshutils.ConnectionCont
|
|||
Code: events.SessionRejectedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: identityContext.Login,
|
||||
User: identityContext.TeleportUser,
|
||||
Login: identityContext.Login,
|
||||
User: identityContext.TeleportUser,
|
||||
Impersonator: identityContext.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
Protocol: events.EventProtocolSSH,
|
||||
|
@ -985,8 +986,9 @@ func (s *Server) HandleNewChan(ctx context.Context, ccx *sshutils.ConnectionCont
|
|||
Code: events.SessionRejectedCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: identityContext.Login,
|
||||
User: identityContext.TeleportUser,
|
||||
Login: identityContext.Login,
|
||||
User: identityContext.TeleportUser,
|
||||
Impersonator: identityContext.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
Protocol: events.EventProtocolSSH,
|
||||
|
@ -1152,8 +1154,9 @@ Loop:
|
|||
Code: events.PortForwardCode,
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
Login: scx.Identity.Login,
|
||||
User: scx.Identity.TeleportUser,
|
||||
Login: scx.Identity.Login,
|
||||
User: scx.Identity.TeleportUser,
|
||||
Impersonator: scx.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: scx.ServerConn.LocalAddr().String(),
|
||||
|
|
|
@ -141,8 +141,9 @@ func (s *SessionRegistry) emitSessionJoinEvent(ctx *ServerContext) {
|
|||
SessionID: string(ctx.SessionID()),
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: ctx.ServerConn.RemoteAddr().String(),
|
||||
|
@ -409,8 +410,9 @@ func (s *SessionRegistry) NotifyWinChange(params rsession.TerminalParams, ctx *S
|
|||
SessionID: string(sid),
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
TerminalSize: params.Serialize(),
|
||||
}
|
||||
|
@ -754,8 +756,9 @@ func (s *session) startInteractive(ch ssh.Channel, ctx *ServerContext) error {
|
|||
SessionID: string(s.id),
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: ctx.ServerConn.RemoteAddr().String(),
|
||||
|
@ -897,8 +900,9 @@ func (s *session) startExec(channel ssh.Channel, ctx *ServerContext) error {
|
|||
SessionID: string(s.id),
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
RemoteAddr: ctx.ServerConn.RemoteAddr().String(),
|
||||
|
@ -992,8 +996,9 @@ func (s *session) startExec(channel ssh.Channel, ctx *ServerContext) error {
|
|||
SessionID: string(s.id),
|
||||
},
|
||||
UserMetadata: events.UserMetadata{
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
User: ctx.Identity.TeleportUser,
|
||||
Login: ctx.Identity.Login,
|
||||
Impersonator: ctx.Identity.Impersonator,
|
||||
},
|
||||
EnhancedRecording: s.hasEnhancedRecording,
|
||||
Interactive: false,
|
||||
|
|
|
@ -80,6 +80,8 @@ type CertAuthority struct {
|
|||
type Identity struct {
|
||||
// Username is a username or name of the node connection
|
||||
Username string
|
||||
// Impersonator is a username of a user impersonating this user
|
||||
Impersonator string
|
||||
// Groups is a list of groups (Teleport roles) encoded in the identity
|
||||
Groups []string
|
||||
// Usage is a list of usage restrictions encoded in the identity
|
||||
|
@ -252,6 +254,10 @@ var (
|
|||
// DatabaseUsersASN1ExtensionOID is an extension OID used when encoding/decoding
|
||||
// allowed database users into certificates.
|
||||
DatabaseUsersASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 2, 6}
|
||||
|
||||
// ImpersonatorASN1ExtensionOID is an extension OID used when encoding/decoding
|
||||
// impersonator user
|
||||
ImpersonatorASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 2, 7}
|
||||
)
|
||||
|
||||
// Subject converts identity to X.509 subject name
|
||||
|
@ -394,6 +400,14 @@ func (id *Identity) Subject() (pkix.Name, error) {
|
|||
})
|
||||
}
|
||||
|
||||
if id.Impersonator != "" {
|
||||
subject.ExtraNames = append(subject.ExtraNames,
|
||||
pkix.AttributeTypeAndValue{
|
||||
Type: ImpersonatorASN1ExtensionOID,
|
||||
Value: id.Impersonator,
|
||||
})
|
||||
}
|
||||
|
||||
return subject, nil
|
||||
}
|
||||
|
||||
|
@ -493,6 +507,11 @@ func FromSubject(subject pkix.Name, expires time.Time) (*Identity, error) {
|
|||
if ok {
|
||||
id.DatabaseUsers = append(id.DatabaseUsers, val)
|
||||
}
|
||||
case attr.Type.Equal(ImpersonatorASN1ExtensionOID):
|
||||
val, ok := attr.Value.(string)
|
||||
if ok {
|
||||
id.Impersonator = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,8 +76,9 @@ func TestKubeExtensions(t *testing.T) {
|
|||
|
||||
expires := clock.Now().Add(time.Hour)
|
||||
identity := Identity{
|
||||
Username: "alice@example.com",
|
||||
Groups: []string{"admin"},
|
||||
Username: "alice@example.com",
|
||||
Groups: []string{"admin"},
|
||||
Impersonator: "bob@example.com",
|
||||
// Generate a certificate restricted for
|
||||
// use against a kubernetes endpoint, and not the API server endpoint
|
||||
// otherwise proxies can generate certs for any user.
|
||||
|
|
|
@ -167,6 +167,35 @@ type Matcher interface {
|
|||
Match(in string) bool
|
||||
}
|
||||
|
||||
// MatcherFn converts function to a matcher interface
|
||||
type MatcherFn func(in string) bool
|
||||
|
||||
// Match matches string against a regexp
|
||||
func (fn MatcherFn) Match(in string) bool {
|
||||
return fn(in)
|
||||
}
|
||||
|
||||
// NewAnyMatcher returns a matcher function based
|
||||
// on incoming values
|
||||
func NewAnyMatcher(in []string) (Matcher, error) {
|
||||
matchers := make([]Matcher, len(in))
|
||||
for i, v := range in {
|
||||
m, err := NewMatcher(v)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
matchers[i] = m
|
||||
}
|
||||
return MatcherFn(func(in string) bool {
|
||||
for _, m := range matchers {
|
||||
if m.Match(in) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}), nil
|
||||
}
|
||||
|
||||
// NewMatcher parses a matcher expression. Currently supported expressions:
|
||||
// - string literal: `foo`
|
||||
// - wildcard expression: `*` or `foo*bar`
|
||||
|
|
Loading…
Reference in a new issue