github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/access_request.go (about) 1 /* 2 Copyright 2020 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package types contains all types and logic required by the Teleport API. 18 package types 19 20 import ( 21 "fmt" 22 "reflect" 23 "slices" 24 "sort" 25 "time" 26 27 "github.com/gravitational/trace" 28 29 "github.com/gravitational/teleport/api/constants" 30 "github.com/gravitational/teleport/api/utils" 31 ) 32 33 // AccessRequest is a request for temporarily granted roles 34 type AccessRequest interface { 35 ResourceWithLabels 36 // GetUser gets the name of the requesting user 37 GetUser() string 38 // GetRoles gets the roles being requested by the user 39 GetRoles() []string 40 // SetRoles overrides the roles being requested by the user 41 SetRoles([]string) 42 // GetState gets the current state of the request 43 GetState() RequestState 44 // SetState sets the approval state of the request 45 SetState(RequestState) error 46 // GetCreationTime gets the time at which the request was 47 // originally registered with the auth server. 48 GetCreationTime() time.Time 49 // SetCreationTime sets the creation time of the request. 50 SetCreationTime(time.Time) 51 // GetAccessExpiry gets the expiration time for the elevated certificate 52 // that will be issued if the Access Request is approved. 53 GetAccessExpiry() time.Time 54 // GetAssumeStartTime gets the time the roles can be assumed 55 // if the Access Request is approved. 56 GetAssumeStartTime() *time.Time 57 // SetAssumeStartTime sets the time the roles can be assumed 58 // if the Access Request is approved. 59 SetAssumeStartTime(time.Time) 60 // SetAccessExpiry sets the expiration time for the elevated certificate 61 // that will be issued if the Access Request is approved. 62 SetAccessExpiry(time.Time) 63 // GetSessionTLL gets the session TTL for generated certificates. 64 GetSessionTLL() time.Time 65 // SetSessionTLL sets the session TTL for generated certificates. 66 SetSessionTLL(time.Time) 67 // GetRequestReason gets the reason for the request's creation. 68 GetRequestReason() string 69 // SetRequestReason sets the reason for the request's creation. 70 SetRequestReason(string) 71 // GetResolveReason gets the reason for the request's resolution. 72 GetResolveReason() string 73 // SetResolveReason sets the reason for the request's resolution. 74 SetResolveReason(string) 75 // GetResolveAnnotations gets the annotations associated with 76 // the request's resolution. 77 GetResolveAnnotations() map[string][]string 78 // SetResolveAnnotations sets the annotations associated with 79 // the request's resolution. 80 SetResolveAnnotations(map[string][]string) 81 // GetSystemAnnotations gets the teleport-applied annotations. 82 GetSystemAnnotations() map[string][]string 83 // SetSystemAnnotations sets the teleport-applied annotations. 84 SetSystemAnnotations(map[string][]string) 85 // GetOriginalRoles gets the original (pre-override) role list. 86 GetOriginalRoles() []string 87 // GetThresholds gets the review thresholds. 88 GetThresholds() []AccessReviewThreshold 89 // SetThresholds sets the review thresholds (internal use only). 90 SetThresholds([]AccessReviewThreshold) 91 // GetRoleThresholdMapping gets the rtm. See documentation of the 92 // AccessRequestSpecV3.RoleThresholdMapping field for details. 93 GetRoleThresholdMapping() map[string]ThresholdIndexSets 94 // SetRoleThresholdMapping sets the rtm (internal use only). See documentation 95 // of the AccessRequestSpecV3.RoleThresholdMapping field for details. 96 SetRoleThresholdMapping(map[string]ThresholdIndexSets) 97 // GetReviews gets the list of currently applied access reviews. 98 GetReviews() []AccessReview 99 // SetReviews sets the list of currently applied access reviews (internal use only). 100 SetReviews([]AccessReview) 101 // GetPromotedAccessListName returns the access list name that this access request 102 // was promoted to. 103 GetPromotedAccessListName() string 104 // SetPromotedAccessListName sets the access list name that this access request 105 // was promoted to. 106 SetPromotedAccessListName(name string) 107 // GetPromotedAccessListTitle returns the access list title that this access request 108 // was promoted to. 109 GetPromotedAccessListTitle() string 110 // SetPromotedAccessListTitle sets the access list title that this access request 111 // was promoted to. 112 SetPromotedAccessListTitle(string) 113 // GetSuggestedReviewers gets the suggested reviewer list. 114 GetSuggestedReviewers() []string 115 // SetSuggestedReviewers sets the suggested reviewer list. 116 SetSuggestedReviewers([]string) 117 // GetRequestedResourceIDs gets the resource IDs to which access is being requested. 118 GetRequestedResourceIDs() []ResourceID 119 // SetRequestedResourceIDs sets the resource IDs to which access is being requested. 120 SetRequestedResourceIDs([]ResourceID) 121 // GetLoginHint gets the requested login hint. 122 GetLoginHint() string 123 // SetLoginHint sets the requested login hint. 124 SetLoginHint(string) 125 // GetMaxDuration gets the maximum time at which the access should be approved for. 126 GetMaxDuration() time.Time 127 // SetMaxDuration sets the maximum time at which the access should be approved for. 128 SetMaxDuration(time.Time) 129 // GetDryRun returns true if this request should not be created and is only 130 // a dry run to validate request capabilities. 131 GetDryRun() bool 132 // SetDryRun sets the dry run flag on the request. 133 SetDryRun(bool) 134 // Copy returns a copy of the access request resource. 135 Copy() AccessRequest 136 } 137 138 // NewAccessRequest assembles an AccessRequest resource. 139 func NewAccessRequest(name string, user string, roles ...string) (AccessRequest, error) { 140 return NewAccessRequestWithResources(name, user, roles, []ResourceID{}) 141 } 142 143 // NewAccessRequestWithResources assembles an AccessRequest resource with 144 // requested resources. 145 func NewAccessRequestWithResources(name string, user string, roles []string, resourceIDs []ResourceID) (AccessRequest, error) { 146 req := AccessRequestV3{ 147 Metadata: Metadata{ 148 Name: name, 149 }, 150 Spec: AccessRequestSpecV3{ 151 User: user, 152 Roles: utils.CopyStrings(roles), 153 RequestedResourceIDs: append([]ResourceID{}, resourceIDs...), 154 }, 155 } 156 if err := req.CheckAndSetDefaults(); err != nil { 157 return nil, trace.Wrap(err) 158 } 159 return &req, nil 160 } 161 162 // GetUser gets User 163 func (r *AccessRequestV3) GetUser() string { 164 return r.Spec.User 165 } 166 167 // GetRoles gets Roles 168 func (r *AccessRequestV3) GetRoles() []string { 169 return r.Spec.Roles 170 } 171 172 // SetRoles sets Roles 173 func (r *AccessRequestV3) SetRoles(roles []string) { 174 r.Spec.Roles = roles 175 } 176 177 // GetState gets State 178 func (r *AccessRequestV3) GetState() RequestState { 179 return r.Spec.State 180 } 181 182 // SetState sets State 183 func (r *AccessRequestV3) SetState(state RequestState) error { 184 if r.Spec.State.IsDenied() { 185 if state.IsDenied() { 186 return nil 187 } 188 return trace.BadParameter("cannot set request-state %q (already denied)", state.String()) 189 } 190 r.Spec.State = state 191 return nil 192 } 193 194 // GetCreationTime gets CreationTime 195 func (r *AccessRequestV3) GetCreationTime() time.Time { 196 return r.Spec.Created 197 } 198 199 // SetCreationTime sets CreationTime 200 func (r *AccessRequestV3) SetCreationTime(t time.Time) { 201 r.Spec.Created = t.UTC() 202 } 203 204 // GetAccessExpiry gets AccessExpiry 205 func (r *AccessRequestV3) GetAccessExpiry() time.Time { 206 return r.Spec.Expires 207 } 208 209 // GetAssumeStartTime gets AssumeStartTime 210 func (r *AccessRequestV3) GetAssumeStartTime() *time.Time { 211 return r.Spec.AssumeStartTime 212 } 213 214 // SetAssumeStartTime sets AssumeStartTime 215 func (r *AccessRequestV3) SetAssumeStartTime(t time.Time) { 216 r.Spec.AssumeStartTime = &t 217 } 218 219 // SetAccessExpiry sets AccessExpiry 220 func (r *AccessRequestV3) SetAccessExpiry(expiry time.Time) { 221 r.Spec.Expires = expiry.UTC() 222 } 223 224 // GetSessionTLL gets SessionTLL 225 func (r *AccessRequestV3) GetSessionTLL() time.Time { 226 return r.Spec.SessionTTL 227 } 228 229 // SetSessionTLL sets SessionTLL 230 func (r *AccessRequestV3) SetSessionTLL(t time.Time) { 231 r.Spec.SessionTTL = t.UTC() 232 } 233 234 // GetRequestReason gets RequestReason 235 func (r *AccessRequestV3) GetRequestReason() string { 236 return r.Spec.RequestReason 237 } 238 239 // SetRequestReason sets RequestReason 240 func (r *AccessRequestV3) SetRequestReason(reason string) { 241 r.Spec.RequestReason = reason 242 } 243 244 // GetResolveReason gets ResolveReason 245 func (r *AccessRequestV3) GetResolveReason() string { 246 return r.Spec.ResolveReason 247 } 248 249 // SetResolveReason sets ResolveReason 250 func (r *AccessRequestV3) SetResolveReason(reason string) { 251 r.Spec.ResolveReason = reason 252 } 253 254 // GetResolveAnnotations gets ResolveAnnotations 255 func (r *AccessRequestV3) GetResolveAnnotations() map[string][]string { 256 return r.Spec.ResolveAnnotations 257 } 258 259 // SetResolveAnnotations sets ResolveAnnotations 260 func (r *AccessRequestV3) SetResolveAnnotations(annotations map[string][]string) { 261 r.Spec.ResolveAnnotations = annotations 262 } 263 264 // GetSystemAnnotations gets SystemAnnotations 265 func (r *AccessRequestV3) GetSystemAnnotations() map[string][]string { 266 return r.Spec.SystemAnnotations 267 } 268 269 // SetSystemAnnotations sets SystemAnnotations 270 func (r *AccessRequestV3) SetSystemAnnotations(annotations map[string][]string) { 271 r.Spec.SystemAnnotations = annotations 272 } 273 274 func (r *AccessRequestV3) GetOriginalRoles() []string { 275 if l := len(r.Spec.RoleThresholdMapping); l == 0 || l == len(r.Spec.Roles) { 276 // rtm is unspecified or original role list is unmodified. since the rtm 277 // keys and role list are identical until role subselection is applied, 278 // we can return the role list directly. 279 return r.Spec.Roles 280 } 281 282 // role subselection has been applied. calculate original roles 283 // by collecting the keys of the rtm. 284 roles := make([]string, 0, len(r.Spec.RoleThresholdMapping)) 285 for role := range r.Spec.RoleThresholdMapping { 286 roles = append(roles, role) 287 } 288 sort.Strings(roles) 289 return roles 290 } 291 292 // GetThresholds gets the review thresholds. 293 func (r *AccessRequestV3) GetThresholds() []AccessReviewThreshold { 294 return r.Spec.Thresholds 295 } 296 297 // SetThresholds sets the review thresholds. 298 func (r *AccessRequestV3) SetThresholds(thresholds []AccessReviewThreshold) { 299 r.Spec.Thresholds = thresholds 300 } 301 302 // GetRoleThresholdMapping gets the rtm. 303 func (r *AccessRequestV3) GetRoleThresholdMapping() map[string]ThresholdIndexSets { 304 return r.Spec.RoleThresholdMapping 305 } 306 307 // SetRoleThresholdMapping sets the rtm (internal use only). 308 func (r *AccessRequestV3) SetRoleThresholdMapping(rtm map[string]ThresholdIndexSets) { 309 r.Spec.RoleThresholdMapping = rtm 310 } 311 312 // SetReviews sets the list of currently applied access reviews. 313 func (r *AccessRequestV3) SetReviews(revs []AccessReview) { 314 utcRevs := make([]AccessReview, len(revs)) 315 for i, rev := range revs { 316 utcRevs[i] = rev 317 utcRevs[i].Created = rev.Created.UTC() 318 } 319 r.Spec.Reviews = utcRevs 320 } 321 322 // GetReviews gets the list of currently applied access reviews. 323 func (r *AccessRequestV3) GetReviews() []AccessReview { 324 return r.Spec.Reviews 325 } 326 327 // GetSuggestedReviewers gets the suggested reviewer list. 328 func (r *AccessRequestV3) GetSuggestedReviewers() []string { 329 return r.Spec.SuggestedReviewers 330 } 331 332 // SetSuggestedReviewers sets the suggested reviewer list. 333 func (r *AccessRequestV3) SetSuggestedReviewers(reviewers []string) { 334 r.Spec.SuggestedReviewers = reviewers 335 } 336 337 // GetPromotedAccessListName returns PromotedAccessListName. 338 func (r *AccessRequestV3) GetPromotedAccessListName() string { 339 if r.Spec.AccessList == nil { 340 return "" 341 } 342 return r.Spec.AccessList.Name 343 } 344 345 // SetPromotedAccessListName sets PromotedAccessListName. 346 func (r *AccessRequestV3) SetPromotedAccessListName(name string) { 347 if r.Spec.AccessList == nil { 348 r.Spec.AccessList = &PromotedAccessList{} 349 } 350 r.Spec.AccessList.Name = name 351 } 352 353 // GetPromotedAccessListTitle returns PromotedAccessListTitle. 354 func (r *AccessRequestV3) GetPromotedAccessListTitle() string { 355 if r.Spec.AccessList == nil { 356 return "" 357 } 358 return r.Spec.AccessList.Title 359 } 360 361 // SetPromotedAccessListTitle sets PromotedAccessListTitle. 362 func (r *AccessRequestV3) SetPromotedAccessListTitle(title string) { 363 if r.Spec.AccessList == nil { 364 r.Spec.AccessList = &PromotedAccessList{} 365 } 366 r.Spec.AccessList.Title = title 367 } 368 369 // setStaticFields sets static resource header and metadata fields. 370 func (r *AccessRequestV3) setStaticFields() { 371 r.Kind = KindAccessRequest 372 r.Version = V3 373 } 374 375 // CheckAndSetDefaults validates set values and sets default values 376 func (r *AccessRequestV3) CheckAndSetDefaults() error { 377 r.setStaticFields() 378 if err := r.Metadata.CheckAndSetDefaults(); err != nil { 379 return trace.Wrap(err) 380 } 381 382 if r.Spec.State.IsNone() { 383 r.Spec.State = RequestState_PENDING 384 } 385 386 if r.GetState().IsPending() { 387 if r.GetResolveReason() != "" { 388 return trace.BadParameter("pending requests cannot include resolve reason") 389 } 390 if len(r.GetResolveAnnotations()) != 0 { 391 return trace.BadParameter("pending requests cannot include resolve annotations") 392 } 393 } 394 395 if r.GetUser() == "" { 396 return trace.BadParameter("access request user name not set") 397 } 398 399 if r.Spec.Roles == nil { 400 r.Spec.Roles = []string{} 401 } 402 if r.Spec.RequestedResourceIDs == nil { 403 r.Spec.RequestedResourceIDs = []ResourceID{} 404 } 405 if len(r.GetRoles()) == 0 && len(r.GetRequestedResourceIDs()) == 0 { 406 return trace.BadParameter("access request does not specify any roles or resources") 407 } 408 409 // dedupe and sort roles to simplify comparing role lists 410 r.Spec.Roles = utils.Deduplicate(r.Spec.Roles) 411 sort.Strings(r.Spec.Roles) 412 413 return nil 414 } 415 416 // GetKind gets Kind 417 func (r *AccessRequestV3) GetKind() string { 418 return r.Kind 419 } 420 421 // GetSubKind gets SubKind 422 func (r *AccessRequestV3) GetSubKind() string { 423 return r.SubKind 424 } 425 426 // SetSubKind sets SubKind 427 func (r *AccessRequestV3) SetSubKind(subKind string) { 428 r.SubKind = subKind 429 } 430 431 // GetVersion gets Version 432 func (r *AccessRequestV3) GetVersion() string { 433 return r.Version 434 } 435 436 // GetName gets Name 437 func (r *AccessRequestV3) GetName() string { 438 return r.Metadata.Name 439 } 440 441 // SetName sets Name 442 func (r *AccessRequestV3) SetName(name string) { 443 r.Metadata.Name = name 444 } 445 446 // Expiry gets Expiry 447 func (r *AccessRequestV3) Expiry() time.Time { 448 return r.Metadata.Expiry() 449 } 450 451 // SetExpiry sets Expiry 452 func (r *AccessRequestV3) SetExpiry(expiry time.Time) { 453 r.Metadata.SetExpiry(expiry.UTC()) 454 } 455 456 // GetMetadata gets Metadata 457 func (r *AccessRequestV3) GetMetadata() Metadata { 458 return r.Metadata 459 } 460 461 // GetResourceID gets ResourceID 462 func (r *AccessRequestV3) GetResourceID() int64 { 463 return r.Metadata.GetID() 464 } 465 466 // SetResourceID sets ResourceID 467 func (r *AccessRequestV3) SetResourceID(id int64) { 468 r.Metadata.SetID(id) 469 } 470 471 // GetRevision returns the revision 472 func (r *AccessRequestV3) GetRevision() string { 473 return r.Metadata.GetRevision() 474 } 475 476 // SetRevision sets the revision 477 func (r *AccessRequestV3) SetRevision(rev string) { 478 r.Metadata.SetRevision(rev) 479 } 480 481 // GetRequestedResourceIDs gets the resource IDs to which access is being requested. 482 func (r *AccessRequestV3) GetRequestedResourceIDs() []ResourceID { 483 return append([]ResourceID{}, r.Spec.RequestedResourceIDs...) 484 } 485 486 // SetRequestedResourceIDs sets the resource IDs to which access is being requested. 487 func (r *AccessRequestV3) SetRequestedResourceIDs(ids []ResourceID) { 488 r.Spec.RequestedResourceIDs = append([]ResourceID{}, ids...) 489 } 490 491 // GetLoginHint gets the requested login hint. 492 func (r *AccessRequestV3) GetLoginHint() string { 493 return r.Spec.LoginHint 494 } 495 496 // SetLoginHint sets the requested login hint. 497 func (r *AccessRequestV3) SetLoginHint(login string) { 498 r.Spec.LoginHint = login 499 } 500 501 // GetDryRun returns true if this request should not be created and is only 502 // a dry run to validate request capabilities. 503 func (r *AccessRequestV3) GetDryRun() bool { 504 return r.Spec.DryRun 505 } 506 507 // GetMaxDuration gets the maximum time at which the access should be approved for. 508 func (r *AccessRequestV3) GetMaxDuration() time.Time { 509 return r.Spec.MaxDuration 510 } 511 512 // SetMaxDuration sets the maximum time at which the access should be approved for. 513 func (r *AccessRequestV3) SetMaxDuration(t time.Time) { 514 r.Spec.MaxDuration = t 515 } 516 517 // SetDryRun sets the dry run flag on the request. 518 func (r *AccessRequestV3) SetDryRun(dryRun bool) { 519 r.Spec.DryRun = dryRun 520 } 521 522 // Copy returns a copy of the access request resource. 523 func (r *AccessRequestV3) Copy() AccessRequest { 524 return utils.CloneProtoMsg(r) 525 } 526 527 // GetLabel retrieves the label with the provided key. If not found 528 // value will be empty and ok will be false. 529 func (r *AccessRequestV3) GetLabel(key string) (value string, ok bool) { 530 v, ok := r.Metadata.Labels[key] 531 return v, ok 532 } 533 534 // GetStaticLabels returns the access request static labels. 535 func (r *AccessRequestV3) GetStaticLabels() map[string]string { 536 return r.Metadata.Labels 537 } 538 539 // SetStaticLabels sets the access request static labels. 540 func (r *AccessRequestV3) SetStaticLabels(sl map[string]string) { 541 r.Metadata.Labels = sl 542 } 543 544 // GetAllLabels returns the access request static labels. 545 func (r *AccessRequestV3) GetAllLabels() map[string]string { 546 return r.Metadata.Labels 547 } 548 549 // MatchSearch goes through select field values and tries to 550 // match against the list of search values. 551 func (r *AccessRequestV3) MatchSearch(values []string) bool { 552 fieldVals := append(utils.MapToStrings(r.GetAllLabels()), r.GetName(), r.GetUser()) 553 fieldVals = append(fieldVals, r.GetRoles()...) 554 for _, resource := range r.GetRequestedResourceIDs() { 555 fieldVals = append(fieldVals, resource.Name) 556 } 557 return MatchSearch(fieldVals, values, nil) 558 } 559 560 // Origin returns the origin value of the resource. 561 func (r *AccessRequestV3) Origin() string { 562 return r.Metadata.Origin() 563 } 564 565 // SetOrigin sets the origin value of the resource. 566 func (r *AccessRequestV3) SetOrigin(origin string) { 567 r.Metadata.SetOrigin(origin) 568 } 569 570 // String returns a text representation of this AccessRequest 571 func (r *AccessRequestV3) String() string { 572 return fmt.Sprintf("AccessRequest(user=%v,roles=%+v)", r.Spec.User, r.Spec.Roles) 573 } 574 575 func (c AccessReviewConditions) IsZero() bool { 576 return reflect.ValueOf(c).IsZero() 577 } 578 579 func (s AccessReviewSubmission) Check() error { 580 if s.RequestID == "" { 581 return trace.BadParameter("missing request ID") 582 } 583 584 return s.Review.Check() 585 } 586 587 func (s AccessReview) Check() error { 588 if s.Author == "" { 589 return trace.BadParameter("missing review author") 590 } 591 592 return nil 593 } 594 595 // GetAccessListName returns the access list name used for the promotion. 596 func (s AccessReview) GetAccessListName() string { 597 if s.AccessList == nil { 598 return "" 599 } 600 return s.AccessList.Name 601 } 602 603 // GetAccessListTitle returns the access list title used for the promotion. 604 func (s AccessReview) GetAccessListTitle() string { 605 if s.AccessList == nil { 606 return "" 607 } 608 return s.AccessList.Title 609 } 610 611 // AccessRequestUpdate encompasses the parameters of a 612 // SetAccessRequestState call. 613 type AccessRequestUpdate struct { 614 // RequestID is the ID of the request to be updated. 615 RequestID string 616 // State is the state that the target request 617 // should resolve to. 618 State RequestState 619 // Reason is an optional description of *why* the 620 // the request is being resolved. 621 Reason string 622 // Annotations supplies extra data associated with 623 // the resolution; primarily for audit purposes. 624 Annotations map[string][]string 625 // Roles, if non-empty declares a list of roles 626 // that should override the role list of the request. 627 // This parameter is only accepted on approvals 628 // and must be a subset of the role list originally 629 // present on the request. 630 Roles []string 631 // AssumeStartTime sets the time the requestor can assume 632 // the requested roles. 633 AssumeStartTime *time.Time 634 } 635 636 // Check validates the request's fields 637 func (u *AccessRequestUpdate) Check() error { 638 if u.RequestID == "" { 639 return trace.BadParameter("missing request id") 640 } 641 if u.State.IsNone() { 642 return trace.BadParameter("missing request state") 643 } 644 if len(u.Roles) > 0 && !u.State.IsApproved() { 645 return trace.BadParameter("cannot override roles when setting state: %s", u.State) 646 } 647 return nil 648 } 649 650 // RequestStrategy is an indicator of how access requests 651 // should be handled for holders of a given role. 652 type RequestStrategy string 653 654 const ( 655 // RequestStrategyOptional is the default request strategy, 656 // indicating that no special actions/requirements exist. 657 RequestStrategyOptional RequestStrategy = "optional" 658 659 // RequestStrategyReason indicates that client implementations 660 // should automatically generate wildcard requests on login, and 661 // users should be prompted for a reason. 662 RequestStrategyReason RequestStrategy = "reason" 663 664 // RequestStrategyAlways indicates that client implementations 665 // should automatically generate wildcard requests on login, but 666 // that reasons are not required. 667 RequestStrategyAlways RequestStrategy = "always" 668 ) 669 670 // ShouldAutoRequest checks if the request strategy 671 // indicates that a request should be automatically 672 // generated on login. 673 func (s RequestStrategy) ShouldAutoRequest() bool { 674 switch s { 675 case RequestStrategyReason, RequestStrategyAlways: 676 return true 677 default: 678 return false 679 } 680 } 681 682 // RequireReason checks if the request strategy 683 // is one that requires users to always supply 684 // reasons with their requests. 685 func (s RequestStrategy) RequireReason() bool { 686 return s == RequestStrategyReason 687 } 688 689 // stateVariants allows iteration of the expected variants 690 // of RequestState. 691 var stateVariants = [5]RequestState{ 692 RequestState_NONE, 693 RequestState_PENDING, 694 RequestState_APPROVED, 695 RequestState_DENIED, 696 RequestState_PROMOTED, 697 } 698 699 // Parse attempts to interpret a value as a string representation 700 // of a RequestState. 701 func (s *RequestState) Parse(val string) error { 702 for _, state := range stateVariants { 703 if state.String() == val { 704 *s = state 705 return nil 706 } 707 } 708 return trace.BadParameter("unknown request state: %q", val) 709 } 710 711 // IsNone request state 712 func (s RequestState) IsNone() bool { 713 return s == RequestState_NONE 714 } 715 716 // IsPending request state 717 func (s RequestState) IsPending() bool { 718 return s == RequestState_PENDING 719 } 720 721 // IsApproved request state 722 func (s RequestState) IsApproved() bool { 723 return s == RequestState_APPROVED 724 } 725 726 // IsDenied request state 727 func (s RequestState) IsDenied() bool { 728 return s == RequestState_DENIED 729 } 730 731 // IsPromoted returns true is the request in the PROMOTED state. 732 func (s RequestState) IsPromoted() bool { 733 return s == RequestState_PROMOTED 734 } 735 736 // IsResolved request state 737 func (s RequestState) IsResolved() bool { 738 return s.IsApproved() || s.IsDenied() || s.IsPromoted() 739 } 740 741 // key values for map encoding of request filter 742 const ( 743 keyID = "id" 744 keyUser = "user" 745 keyState = "state" 746 ) 747 748 // IntoMap copies AccessRequestFilter values into a map 749 func (f *AccessRequestFilter) IntoMap() map[string]string { 750 m := make(map[string]string) 751 if f.ID != "" { 752 m[keyID] = f.ID 753 } 754 if f.User != "" { 755 m[keyUser] = f.User 756 } 757 if !f.State.IsNone() { 758 m[keyState] = f.State.String() 759 } 760 return m 761 } 762 763 // FromMap copies values from a map into this AccessRequestFilter value 764 func (f *AccessRequestFilter) FromMap(m map[string]string) error { 765 for key, val := range m { 766 switch key { 767 case keyID: 768 f.ID = val 769 case keyUser: 770 f.User = val 771 case keyState: 772 if err := f.State.Parse(val); err != nil { 773 return trace.Wrap(err) 774 } 775 default: 776 return trace.BadParameter("unknown filter key %s", key) 777 } 778 } 779 return nil 780 } 781 782 func hasReviewed(req AccessRequest, author string) bool { 783 reviews := req.GetReviews() 784 var reviewers []string 785 for _, review := range reviews { 786 reviewers = append(reviewers, review.Author) 787 } 788 return slices.Contains(reviewers, author) 789 } 790 791 // Match checks if a given access request matches this filter. 792 func (f *AccessRequestFilter) Match(req AccessRequest) bool { 793 // only return if the request was made by the api requester 794 if f.Scope == AccessRequestScope_MY_REQUESTS && req.GetUser() != f.Requester { 795 return false 796 } 797 // a user cannot review their own requests 798 if f.Scope == AccessRequestScope_NEEDS_REVIEW { 799 if req.GetUser() == f.Requester { 800 return false 801 } 802 if req.GetState() != RequestState_PENDING { 803 return false 804 } 805 if hasReviewed(req, f.Requester) { 806 return false 807 } 808 } 809 // only match if the api requester has submit a review 810 if f.Scope == AccessRequestScope_REVIEWED { 811 // users cant review their own requests so we can early return 812 if req.GetUser() == f.Requester { 813 return false 814 } 815 if !hasReviewed(req, f.Requester) { 816 return false 817 } 818 } 819 if !req.MatchSearch(f.SearchKeywords) { 820 return false 821 } 822 if f.ID != "" && req.GetName() != f.ID { 823 return false 824 } 825 if f.User != "" && req.GetUser() != f.User { 826 return false 827 } 828 if !f.State.IsNone() && req.GetState() != f.State { 829 return false 830 } 831 return true 832 } 833 834 // AccessRequests is a list of AccessRequest resources. 835 type AccessRequests []AccessRequest 836 837 // ToMap returns these access requests as a map keyed by access request name. 838 func (a AccessRequests) ToMap() map[string]AccessRequest { 839 m := make(map[string]AccessRequest) 840 for _, accessRequest := range a { 841 m[accessRequest.GetName()] = accessRequest 842 } 843 return m 844 } 845 846 // AsResources returns these access requests as resources with labels. 847 func (a AccessRequests) AsResources() (resources ResourcesWithLabels) { 848 for _, accessRequest := range a { 849 resources = append(resources, accessRequest) 850 } 851 return resources 852 } 853 854 // Len returns the slice length. 855 func (a AccessRequests) Len() int { return len(a) } 856 857 // Less compares access requests by name. 858 func (a AccessRequests) Less(i, j int) bool { return a[i].GetName() < a[j].GetName() } 859 860 // Swap swaps two access requests. 861 func (a AccessRequests) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 862 863 // NewAccessRequestAllowedPromotions returns a new AccessRequestAllowedPromotions resource. 864 func NewAccessRequestAllowedPromotions(promotions []*AccessRequestAllowedPromotion) *AccessRequestAllowedPromotions { 865 if promotions == nil { 866 promotions = make([]*AccessRequestAllowedPromotion, 0) 867 } 868 869 return &AccessRequestAllowedPromotions{ 870 Promotions: promotions, 871 } 872 } 873 874 // ValidateAssumeStartTime returns error if start time is in an invalid range. 875 func ValidateAssumeStartTime(assumeStartTime time.Time, accessExpiry time.Time, creationTime time.Time) error { 876 // Guard against requesting a start time before the request creation time. 877 if assumeStartTime.Before(creationTime) { 878 return trace.BadParameter("assume start time has to be after %v", creationTime.Format(time.RFC3339)) 879 } 880 // Guard against requesting a start time after access expiry. 881 if assumeStartTime.After(accessExpiry) || assumeStartTime.Equal(accessExpiry) { 882 return trace.BadParameter("assume start time must be prior to access expiry time at %v", 883 accessExpiry.Format(time.RFC3339)) 884 } 885 // Access expiry can be greater than constants.MaxAssumeStartDuration, but start time 886 // should be on or before constants.MaxAssumeStartDuration. 887 maxAssumableStartTime := creationTime.Add(constants.MaxAssumeStartDuration) 888 if maxAssumableStartTime.Before(accessExpiry) && assumeStartTime.After(maxAssumableStartTime) { 889 return trace.BadParameter("assume start time is too far in the future, latest time allowed is %v", 890 maxAssumableStartTime.Format(time.RFC3339)) 891 } 892 893 return nil 894 }