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  }