github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/okta.go (about) 1 /* 2 Copyright 2023 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 18 19 import ( 20 "fmt" 21 "time" 22 23 "github.com/gravitational/trace" 24 25 "github.com/gravitational/teleport/api/constants" 26 "github.com/gravitational/teleport/api/types/compare" 27 "github.com/gravitational/teleport/api/utils" 28 ) 29 30 var _ compare.IsEqual[OktaAssignment] = (*OktaAssignmentV1)(nil) 31 32 // OktaImportRule specifies a rule for importing and labeling Okta applications and groups. 33 type OktaImportRule interface { 34 ResourceWithLabels 35 36 // GetPriority will return the priority of the Okta import rule. 37 GetPriority() int32 38 39 // GetMappings will return the list of mappings for the Okta import rule. 40 GetMappings() []OktaImportRuleMapping 41 } 42 43 // NewOktaImportRule returns a new OktaImportRule. 44 func NewOktaImportRule(metadata Metadata, spec OktaImportRuleSpecV1) (OktaImportRule, error) { 45 o := &OktaImportRuleV1{ 46 ResourceHeader: ResourceHeader{ 47 Metadata: metadata, 48 }, 49 Spec: spec, 50 } 51 if err := o.CheckAndSetDefaults(); err != nil { 52 return nil, trace.Wrap(err) 53 } 54 return o, nil 55 } 56 57 // GetPriority will return the priority of the Okta import rule. 58 func (o *OktaImportRuleV1) GetPriority() int32 { 59 return o.Spec.Priority 60 } 61 62 // GetMappings will return the list of mappings for the Okta import rule. 63 func (o *OktaImportRuleV1) GetMappings() []OktaImportRuleMapping { 64 matches := make([]OktaImportRuleMapping, len(o.Spec.Mappings)) 65 66 for i, match := range o.Spec.Mappings { 67 matches[i] = match 68 } 69 70 return matches 71 } 72 73 // String returns the Okta import rule string representation. 74 func (o *OktaImportRuleV1) String() string { 75 return fmt.Sprintf("OktaImportRuleV1(Name=%v, Labels=%v)", 76 o.GetName(), o.GetAllLabels()) 77 } 78 79 // MatchSearch goes through select field values and tries to 80 // match against the list of search values. 81 func (o *OktaImportRuleV1) MatchSearch(values []string) bool { 82 fieldVals := append(utils.MapToStrings(o.GetAllLabels()), o.GetName()) 83 return MatchSearch(fieldVals, values, nil) 84 } 85 86 // setStaticFields sets static resource header and metadata fields. 87 func (o *OktaImportRuleV1) setStaticFields() { 88 o.Kind = KindOktaImportRule 89 o.Version = V1 90 } 91 92 // CheckAndSetDefaults checks and sets default values 93 func (o *OktaImportRuleV1) CheckAndSetDefaults() error { 94 o.setStaticFields() 95 if err := o.Metadata.CheckAndSetDefaults(); err != nil { 96 return trace.Wrap(err) 97 } 98 99 if o.Spec.Priority < 0 { 100 return trace.BadParameter("priority must be a positive number") 101 } 102 103 if len(o.Spec.Mappings) == 0 { 104 return trace.BadParameter("mappings is empty") 105 } 106 107 for _, mapping := range o.Spec.Mappings { 108 if err := mapping.CheckAndSetDefaults(); err != nil { 109 return trace.Wrap(err) 110 } 111 } 112 113 return nil 114 } 115 116 // OktaImportRuleMapping is a list of matches that map match rules to labels. 117 type OktaImportRuleMapping interface { 118 // GetMatches returns all matches for a mapping. 119 GetMatches() []OktaImportRuleMatch 120 // GetAddLabels returns the labels that will be added for a mapping. 121 GetAddLabels() map[string]string 122 } 123 124 // GetMatches returns all matches for a mapping. 125 func (o *OktaImportRuleMappingV1) GetMatches() []OktaImportRuleMatch { 126 matches := make([]OktaImportRuleMatch, len(o.Match)) 127 128 for i, match := range o.Match { 129 matches[i] = match 130 } 131 132 return matches 133 } 134 135 // GetAddLabels returns the labels that will be added for a mapping. 136 func (o *OktaImportRuleMappingV1) GetAddLabels() map[string]string { 137 return o.AddLabels 138 } 139 140 // CheckAndSetDefaults checks and sets default values 141 func (o *OktaImportRuleMappingV1) CheckAndSetDefaults() error { 142 for _, match := range o.Match { 143 if err := match.CheckAndSetDefaults(); err != nil { 144 return trace.Wrap(err) 145 } 146 } 147 148 return nil 149 } 150 151 // OktaImportRuleMatch creates a new Okta import rule match. 152 type OktaImportRuleMatch interface { 153 // GetAppIDs returns whether or not this match contains an App ID match and, if so, the list of app IDs. 154 GetAppIDs() (bool, []string) 155 // GetGroupIDs returns whether or not this match contains a Group ID match and, if so, the list of app IDs. 156 GetGroupIDs() (bool, []string) 157 // GetAppNameRegexes returns whether or not this match contains app name regexes and, if so, the regexes. 158 GetAppNameRegexes() (bool, []string) 159 // GetGroupNameRegexes returns whether or not this match contains group name regexes and, if so, the regexes. 160 GetGroupNameRegexes() (bool, []string) 161 } 162 163 // GetAppIDs returns whether or not this match contains an App ID match and, if so, the list of app IDs. 164 func (o *OktaImportRuleMatchV1) GetAppIDs() (bool, []string) { 165 return len(o.AppIDs) > 0, o.AppIDs 166 } 167 168 // GetGroupIDs returns whether or not this match contains a Group ID match and, if so, the list of app IDs. 169 func (o *OktaImportRuleMatchV1) GetGroupIDs() (bool, []string) { 170 return len(o.GroupIDs) > 0, o.GroupIDs 171 } 172 173 // GetAppNameRegexes returns whether or not this match contains app name regexes and, if so, the regexes. 174 func (o *OktaImportRuleMatchV1) GetAppNameRegexes() (bool, []string) { 175 return len(o.AppNameRegexes) > 0, o.AppNameRegexes 176 } 177 178 // GetGroupNameRegexes returns whether or not this match contains group name regexes and, if so, the regexes. 179 func (o *OktaImportRuleMatchV1) GetGroupNameRegexes() (bool, []string) { 180 return len(o.GroupNameRegexes) > 0, o.GroupNameRegexes 181 } 182 183 // CheckAndSetDefaults checks and sets default values 184 func (o *OktaImportRuleMatchV1) CheckAndSetDefaults() error { 185 if len(o.AppIDs) > 0 && len(o.GroupIDs) > 0 { 186 return trace.BadParameter("only one of App IDs or Group IDs can be set") 187 } 188 189 return nil 190 } 191 192 // OktaAssignment is a representation of an action or set of actions taken by Teleport to assign Okta users 193 // to applications or groups. When modifying this object, please make sure to update 194 // tool/tctl/common/oktaassignment to reflect any new fields that were added. 195 type OktaAssignment interface { 196 ResourceWithLabels 197 198 // SetMetadata will set the metadata for the Okta assignment. 199 SetMetadata(metadata Metadata) 200 // GetUser will return the user that the Okta assignment actions applies to. 201 GetUser() string 202 // GetTargets will return the list of targets that will be assigned as part of this assignment. 203 GetTargets() []OktaAssignmentTarget 204 // GetCleanupTime will return the optional time that the assignment should be cleaned up. 205 GetCleanupTime() time.Time 206 // SetCleanupTime will set the cleanup time. 207 SetCleanupTime(time.Time) 208 // GetStatus gets the status of the assignment. 209 GetStatus() string 210 // SetStatus sets the status of the eassignment. Only allows valid transitions. 211 SetStatus(status string) error 212 // SetLastTransition sets the last transition time. 213 SetLastTransition(time.Time) 214 // GetLastTransition returns the time that the action last transitioned. 215 GetLastTransition() time.Time 216 // IsFinalized returns the finalized state. 217 IsFinalized() bool 218 // SetFinalized sets the finalized state 219 SetFinalized(bool) 220 // Copy returns a copy of this Okta assignment resource. 221 Copy() OktaAssignment 222 } 223 224 // NewOktaAssignment creates a new Okta assignment object. 225 func NewOktaAssignment(metadata Metadata, spec OktaAssignmentSpecV1) (OktaAssignment, error) { 226 o := &OktaAssignmentV1{ 227 ResourceHeader: ResourceHeader{ 228 Metadata: metadata, 229 }, 230 Spec: spec, 231 } 232 if err := o.CheckAndSetDefaults(); err != nil { 233 return nil, trace.Wrap(err) 234 } 235 return o, nil 236 } 237 238 // SetMetadata will set the metadata for the Okta assignment. 239 func (o *OktaAssignmentV1) SetMetadata(metadata Metadata) { 240 o.Metadata = metadata 241 } 242 243 // GetUser returns the user that the actions will be applied to. 244 func (o *OktaAssignmentV1) GetUser() string { 245 return o.Spec.User 246 } 247 248 // GetTargets returns the targets associated with the Okta assignment. 249 func (o *OktaAssignmentV1) GetTargets() []OktaAssignmentTarget { 250 targets := make([]OktaAssignmentTarget, len(o.Spec.Targets)) 251 252 for i, target := range o.Spec.Targets { 253 targets[i] = target 254 } 255 256 return targets 257 } 258 259 // GetCleanupTime will return the optional time that the assignment should be cleaned up. 260 func (o *OktaAssignmentV1) GetCleanupTime() time.Time { 261 return o.Spec.CleanupTime 262 } 263 264 // SetCleanupTime will set the cleanup time. 265 func (o *OktaAssignmentV1) SetCleanupTime(cleanupTime time.Time) { 266 o.Spec.CleanupTime = cleanupTime.UTC() 267 } 268 269 // GetStatus gets the status of the assignment. 270 func (o *OktaAssignmentV1) GetStatus() string { 271 switch o.Spec.Status { 272 case OktaAssignmentSpecV1_PENDING: 273 return constants.OktaAssignmentStatusPending 274 case OktaAssignmentSpecV1_PROCESSING: 275 return constants.OktaAssignmentStatusProcessing 276 case OktaAssignmentSpecV1_SUCCESSFUL: 277 return constants.OktaAssignmentStatusSuccessful 278 case OktaAssignmentSpecV1_FAILED: 279 return constants.OktaAssignmentStatusFailed 280 default: 281 return constants.OktaAssignmentStatusUnknown 282 } 283 } 284 285 // SetStatus sets the status of the eassignment. Only allows valid transitions. 286 // 287 // Valid transitions are: 288 // * PENDING -> (PROCESSING) 289 // * PROCESSING -> (SUCCESSFUL, FAILED, PROCESSING) 290 // * SUCCESSFUL -> (PROCESSING) 291 // * FAILED -> (PROCESSING) 292 func (o *OktaAssignmentV1) SetStatus(status string) error { 293 invalidTransition := false 294 switch o.Spec.Status { 295 case OktaAssignmentSpecV1_PENDING: 296 switch status { 297 case constants.OktaAssignmentStatusProcessing: 298 default: 299 invalidTransition = true 300 } 301 case OktaAssignmentSpecV1_PROCESSING: 302 switch status { 303 case constants.OktaAssignmentStatusProcessing: 304 case constants.OktaAssignmentStatusSuccessful: 305 case constants.OktaAssignmentStatusFailed: 306 default: 307 invalidTransition = true 308 } 309 case OktaAssignmentSpecV1_SUCCESSFUL: 310 switch status { 311 case constants.OktaAssignmentStatusProcessing: 312 default: 313 invalidTransition = true 314 } 315 case OktaAssignmentSpecV1_FAILED: 316 switch status { 317 case constants.OktaAssignmentStatusProcessing: 318 default: 319 invalidTransition = true 320 } 321 case OktaAssignmentSpecV1_UNKNOWN: 322 // All transitions are allowed from UNKNOWN. 323 default: 324 invalidTransition = true 325 } 326 327 if invalidTransition { 328 return trace.BadParameter("invalid transition: %s -> %s", o.GetStatus(), status) 329 } 330 331 o.Spec.Status = OktaAssignmentStatusToProto(status) 332 333 return nil 334 } 335 336 // SetLastTransition sets the last transition time. 337 func (o *OktaAssignmentV1) SetLastTransition(time time.Time) { 338 o.Spec.LastTransition = time.UTC() 339 } 340 341 // GetLastTransition returns the optional time that the action last transitioned. 342 func (o *OktaAssignmentV1) GetLastTransition() time.Time { 343 return o.Spec.LastTransition 344 } 345 346 // IsFinalized returns the finalized state. 347 func (o *OktaAssignmentV1) IsFinalized() bool { 348 return o.Spec.Finalized 349 } 350 351 // SetFinalized sets the finalized state 352 func (o *OktaAssignmentV1) SetFinalized(finalized bool) { 353 o.Spec.Finalized = finalized 354 } 355 356 // Copy returns a copy of this Okta assignment resource. 357 func (o *OktaAssignmentV1) Copy() OktaAssignment { 358 return utils.CloneProtoMsg(o) 359 } 360 361 // String returns the Okta assignment rule string representation. 362 func (o *OktaAssignmentV1) String() string { 363 return fmt.Sprintf("OktaAssignmentV1(Name=%v, Labels=%v)", 364 o.GetName(), o.GetAllLabels()) 365 } 366 367 // MatchSearch goes through select field values and tries to 368 // match against the list of search values. 369 func (o *OktaAssignmentV1) MatchSearch(values []string) bool { 370 fieldVals := append(utils.MapToStrings(o.GetAllLabels()), o.GetName()) 371 return MatchSearch(fieldVals, values, nil) 372 } 373 374 // setStaticFields sets static resource header and metadata fields. 375 func (o *OktaAssignmentV1) setStaticFields() { 376 o.Kind = KindOktaAssignment 377 o.Version = V1 378 } 379 380 // CheckAndSetDefaults checks and sets default values 381 func (o *OktaAssignmentV1) CheckAndSetDefaults() error { 382 o.setStaticFields() 383 if err := o.Metadata.CheckAndSetDefaults(); err != nil { 384 return trace.Wrap(err) 385 } 386 387 if o.Spec.User == "" { 388 return trace.BadParameter("user must not be empty") 389 } 390 391 // Make sure the times are UTC so that Copy() works properly. 392 o.Spec.CleanupTime = o.Spec.CleanupTime.UTC() 393 o.Spec.LastTransition = o.Spec.LastTransition.UTC() 394 395 return nil 396 } 397 398 // IsEqual determines if two okta assignment resources are equivalent to one another. 399 func (o *OktaAssignmentV1) IsEqual(i OktaAssignment) bool { 400 if other, ok := i.(*OktaAssignmentV1); ok { 401 return deriveTeleportEqualOktaAssignmentV1(o, other) 402 } 403 return false 404 } 405 406 // OktaAssignmentTarget is an target for an Okta assignment. 407 type OktaAssignmentTarget interface { 408 // GetTargetType returns the target type. 409 GetTargetType() string 410 // GetID returns the ID of the target. 411 GetID() string 412 } 413 414 // GetTargetType returns the target type. 415 func (o *OktaAssignmentTargetV1) GetTargetType() string { 416 switch o.Type { 417 case OktaAssignmentTargetV1_APPLICATION: 418 return constants.OktaAssignmentTargetApplication 419 case OktaAssignmentTargetV1_GROUP: 420 return constants.OktaAssignmentTargetGroup 421 default: 422 return constants.OktaAssignmentTargetUnknown 423 } 424 } 425 426 // GetID returns the ID of the action target. 427 func (o *OktaAssignmentTargetV1) GetID() string { 428 return o.Id 429 } 430 431 // OktaAssignments is a list of OktaAssignment resources. 432 type OktaAssignments []OktaAssignment 433 434 // ToMap returns these Okta assignments as a map keyed by Okta assignment name. 435 func (o OktaAssignments) ToMap() map[string]OktaAssignment { 436 m := make(map[string]OktaAssignment, len(o)) 437 for _, oktaAssignment := range o { 438 m[oktaAssignment.GetName()] = oktaAssignment 439 } 440 return m 441 } 442 443 // AsResources returns these Okta assignments as resources with labels. 444 func (o OktaAssignments) AsResources() ResourcesWithLabels { 445 resources := make(ResourcesWithLabels, 0, len(o)) 446 for _, oktaAssignment := range o { 447 resources = append(resources, oktaAssignment) 448 } 449 return resources 450 } 451 452 // Len returns the slice length. 453 func (o OktaAssignments) Len() int { return len(o) } 454 455 // Less compares Okta assignments by name. 456 func (o OktaAssignments) Less(i, j int) bool { return o[i].GetName() < o[j].GetName() } 457 458 // Swap swaps two Okta assignments. 459 func (o OktaAssignments) Swap(i, j int) { o[i], o[j] = o[j], o[i] } 460 461 // OktaAssignmentStatusToProto will convert the internal notion of an Okta status into the Okta status 462 // message understood by protobuf. 463 func OktaAssignmentStatusToProto(status string) OktaAssignmentSpecV1_OktaAssignmentStatus { 464 switch status { 465 case constants.OktaAssignmentStatusPending: 466 return OktaAssignmentSpecV1_PENDING 467 case constants.OktaAssignmentStatusProcessing: 468 return OktaAssignmentSpecV1_PROCESSING 469 case constants.OktaAssignmentStatusSuccessful: 470 return OktaAssignmentSpecV1_SUCCESSFUL 471 case constants.OktaAssignmentStatusFailed: 472 return OktaAssignmentSpecV1_FAILED 473 default: 474 return OktaAssignmentSpecV1_UNKNOWN 475 } 476 } 477 478 // OktaAssignmentStatusProtoToString will convert the Okta status known to protobuf into the internal notion 479 // of an Okta status. 480 func OktaAssignmentStatusProtoToString(status OktaAssignmentSpecV1_OktaAssignmentStatus) string { 481 switch status { 482 case OktaAssignmentSpecV1_PENDING: 483 return constants.OktaAssignmentStatusPending 484 case OktaAssignmentSpecV1_PROCESSING: 485 return constants.OktaAssignmentStatusProcessing 486 case OktaAssignmentSpecV1_SUCCESSFUL: 487 return constants.OktaAssignmentStatusSuccessful 488 case OktaAssignmentSpecV1_FAILED: 489 return constants.OktaAssignmentStatusFailed 490 default: 491 return constants.OktaAssignmentStatusUnknown 492 } 493 }