github.com/pluralsh/plural-cli@v0.9.5/pkg/bundle/oidc.go (about)

     1  package bundle
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/AlecAivazis/survey/v2"
     8  
     9  	"github.com/pluralsh/plural-cli/pkg/api"
    10  	"github.com/pluralsh/plural-cli/pkg/manifest"
    11  	"github.com/pluralsh/plural-cli/pkg/utils"
    12  )
    13  
    14  var oidcConfirmed bool
    15  
    16  func ConfigureOidc(repo string, client api.Client, recipe *api.Recipe, ctx map[string]interface{}, confirm *bool) error {
    17  	if recipe.OidcSettings == nil {
    18  		return nil
    19  	}
    20  
    21  	ok, err := confirmOidc(confirm)
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	if !ok {
    27  		return nil
    28  	}
    29  
    30  	settings := recipe.OidcSettings
    31  	redirectUris, err := formatRedirectUris(settings, ctx)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	inst, err := client.GetInstallation(repo)
    37  	if err != nil {
    38  		return api.GetErrorResponse(err, "GetInstallation")
    39  	}
    40  
    41  	me, err := client.Me()
    42  	if err != nil {
    43  		return api.GetErrorResponse(err, "Me")
    44  	}
    45  
    46  	oidcSettings := &api.OidcProviderAttributes{
    47  		RedirectUris: redirectUris,
    48  		AuthMethod:   settings.AuthMethod,
    49  		Bindings: []api.Binding{
    50  			{UserId: me.Id},
    51  		},
    52  	}
    53  	mergeOidcAttributes(inst, oidcSettings)
    54  	err = client.OIDCProvider(inst.Id, oidcSettings)
    55  	return api.GetErrorResponse(err, "OIDCProvider")
    56  }
    57  
    58  func SetupOIDC(repo string, client api.Client, redirectUris []string, authMethod string) error {
    59  	inst, err := client.GetInstallation(repo)
    60  	if err != nil {
    61  		return api.GetErrorResponse(err, "GetInstallation")
    62  	}
    63  
    64  	me, err := client.Me()
    65  	if err != nil {
    66  		return api.GetErrorResponse(err, "Me")
    67  	}
    68  
    69  	oidcSettings := &api.OidcProviderAttributes{
    70  		RedirectUris: redirectUris,
    71  		AuthMethod:   authMethod,
    72  		Bindings: []api.Binding{
    73  			{UserId: me.Id},
    74  		},
    75  	}
    76  	mergeOidcAttributes(inst, oidcSettings)
    77  	err = client.OIDCProvider(inst.Id, oidcSettings)
    78  	return api.GetErrorResponse(err, "OIDCProvider")
    79  }
    80  
    81  func mergeOidcAttributes(inst *api.Installation, attributes *api.OidcProviderAttributes) {
    82  	if inst.OIDCProvider == nil {
    83  		return
    84  	}
    85  
    86  	provider := inst.OIDCProvider
    87  	attributes.RedirectUris = utils.Dedupe(append(attributes.RedirectUris, provider.RedirectUris...))
    88  	bindings := attributes.Bindings
    89  	for _, val := range provider.Bindings {
    90  		// attributes is only pre-populated with the current user right now
    91  		if val.User != nil && val.User.Id != attributes.Bindings[0].UserId {
    92  			bindings = append(bindings, api.Binding{UserId: val.User.Id})
    93  		} else if val.Group != nil {
    94  			bindings = append(bindings, api.Binding{GroupId: val.Group.Id})
    95  		}
    96  	}
    97  	attributes.Bindings = bindings
    98  }
    99  
   100  func formatRedirectUris(settings *api.OIDCSettings, ctx map[string]interface{}) ([]string, error) {
   101  	res := make([]string, 0)
   102  	domain := ""
   103  
   104  	if settings.DomainKey != "" {
   105  		d, ok := ctx[settings.DomainKey]
   106  		if !ok {
   107  			return res, fmt.Errorf("No domain setting for %s in context", settings.DomainKey)
   108  		}
   109  
   110  		domain = d.(string)
   111  	}
   112  
   113  	proj, err := manifest.FetchProject()
   114  	if err != nil {
   115  		return res, err
   116  	}
   117  
   118  	fmtUri := func(uri string) string {
   119  		if domain != "" {
   120  			uri = strings.ReplaceAll(uri, "{domain}", domain)
   121  		}
   122  
   123  		if settings.Subdomain {
   124  			uri = strings.ReplaceAll(uri, "{subdomain}", proj.Network.Subdomain)
   125  		}
   126  
   127  		return uri
   128  	}
   129  
   130  	if settings.UriFormat != "" {
   131  		return []string{fmtUri(settings.UriFormat)}, err
   132  	}
   133  
   134  	for _, uri := range settings.UriFormats {
   135  		res = append(res, fmtUri(uri))
   136  	}
   137  
   138  	return res, nil
   139  }
   140  
   141  func confirmOidc(confirm *bool) (bool, error) {
   142  	if confirm != nil && *confirm {
   143  		oidcConfirmed = true
   144  	}
   145  
   146  	if oidcConfirmed {
   147  		return true, nil
   148  	}
   149  
   150  	value, ok := utils.GetEnvBoolValue("PLURAL_CONFIRM_OIDC")
   151  	if ok {
   152  		confirm = &value
   153  	} else {
   154  		if err := survey.AskOne(&survey.Confirm{
   155  			Message: "Enable plural OIDC",
   156  			Default: true,
   157  		}, confirm, survey.WithValidator(survey.Required)); err != nil {
   158  			return false, err
   159  		}
   160  	}
   161  
   162  	return *confirm, nil
   163  }