code.gitea.io/gitea@v1.22.3/cmd/admin_auth_oauth.go (about)

     1  // Copyright 2023 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package cmd
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"net/url"
    10  
    11  	auth_model "code.gitea.io/gitea/models/auth"
    12  	"code.gitea.io/gitea/services/auth/source/oauth2"
    13  
    14  	"github.com/urfave/cli/v2"
    15  )
    16  
    17  var (
    18  	oauthCLIFlags = []cli.Flag{
    19  		&cli.StringFlag{
    20  			Name:  "name",
    21  			Value: "",
    22  			Usage: "Application Name",
    23  		},
    24  		&cli.StringFlag{
    25  			Name:  "provider",
    26  			Value: "",
    27  			Usage: "OAuth2 Provider",
    28  		},
    29  		&cli.StringFlag{
    30  			Name:  "key",
    31  			Value: "",
    32  			Usage: "Client ID (Key)",
    33  		},
    34  		&cli.StringFlag{
    35  			Name:  "secret",
    36  			Value: "",
    37  			Usage: "Client Secret",
    38  		},
    39  		&cli.StringFlag{
    40  			Name:  "auto-discover-url",
    41  			Value: "",
    42  			Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)",
    43  		},
    44  		&cli.StringFlag{
    45  			Name:  "use-custom-urls",
    46  			Value: "false",
    47  			Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
    48  		},
    49  		&cli.StringFlag{
    50  			Name:  "custom-tenant-id",
    51  			Value: "",
    52  			Usage: "Use custom Tenant ID for OAuth endpoints",
    53  		},
    54  		&cli.StringFlag{
    55  			Name:  "custom-auth-url",
    56  			Value: "",
    57  			Usage: "Use a custom Authorization URL (option for GitLab/GitHub)",
    58  		},
    59  		&cli.StringFlag{
    60  			Name:  "custom-token-url",
    61  			Value: "",
    62  			Usage: "Use a custom Token URL (option for GitLab/GitHub)",
    63  		},
    64  		&cli.StringFlag{
    65  			Name:  "custom-profile-url",
    66  			Value: "",
    67  			Usage: "Use a custom Profile URL (option for GitLab/GitHub)",
    68  		},
    69  		&cli.StringFlag{
    70  			Name:  "custom-email-url",
    71  			Value: "",
    72  			Usage: "Use a custom Email URL (option for GitHub)",
    73  		},
    74  		&cli.StringFlag{
    75  			Name:  "icon-url",
    76  			Value: "",
    77  			Usage: "Custom icon URL for OAuth2 login source",
    78  		},
    79  		&cli.BoolFlag{
    80  			Name:  "skip-local-2fa",
    81  			Usage: "Set to true to skip local 2fa for users authenticated by this source",
    82  		},
    83  		&cli.StringSliceFlag{
    84  			Name:  "scopes",
    85  			Value: nil,
    86  			Usage: "Scopes to request when to authenticate against this OAuth2 source",
    87  		},
    88  		&cli.StringFlag{
    89  			Name:  "required-claim-name",
    90  			Value: "",
    91  			Usage: "Claim name that has to be set to allow users to login with this source",
    92  		},
    93  		&cli.StringFlag{
    94  			Name:  "required-claim-value",
    95  			Value: "",
    96  			Usage: "Claim value that has to be set to allow users to login with this source",
    97  		},
    98  		&cli.StringFlag{
    99  			Name:  "group-claim-name",
   100  			Value: "",
   101  			Usage: "Claim name providing group names for this source",
   102  		},
   103  		&cli.StringFlag{
   104  			Name:  "admin-group",
   105  			Value: "",
   106  			Usage: "Group Claim value for administrator users",
   107  		},
   108  		&cli.StringFlag{
   109  			Name:  "restricted-group",
   110  			Value: "",
   111  			Usage: "Group Claim value for restricted users",
   112  		},
   113  		&cli.StringFlag{
   114  			Name:  "group-team-map",
   115  			Value: "",
   116  			Usage: "JSON mapping between groups and org teams",
   117  		},
   118  		&cli.BoolFlag{
   119  			Name:  "group-team-map-removal",
   120  			Usage: "Activate automatic team membership removal depending on groups",
   121  		},
   122  	}
   123  
   124  	microcmdAuthAddOauth = &cli.Command{
   125  		Name:   "add-oauth",
   126  		Usage:  "Add new Oauth authentication source",
   127  		Action: runAddOauth,
   128  		Flags:  oauthCLIFlags,
   129  	}
   130  
   131  	microcmdAuthUpdateOauth = &cli.Command{
   132  		Name:   "update-oauth",
   133  		Usage:  "Update existing Oauth authentication source",
   134  		Action: runUpdateOauth,
   135  		Flags:  append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
   136  	}
   137  )
   138  
   139  func parseOAuth2Config(c *cli.Context) *oauth2.Source {
   140  	var customURLMapping *oauth2.CustomURLMapping
   141  	if c.IsSet("use-custom-urls") {
   142  		customURLMapping = &oauth2.CustomURLMapping{
   143  			TokenURL:   c.String("custom-token-url"),
   144  			AuthURL:    c.String("custom-auth-url"),
   145  			ProfileURL: c.String("custom-profile-url"),
   146  			EmailURL:   c.String("custom-email-url"),
   147  			Tenant:     c.String("custom-tenant-id"),
   148  		}
   149  	} else {
   150  		customURLMapping = nil
   151  	}
   152  	return &oauth2.Source{
   153  		Provider:                      c.String("provider"),
   154  		ClientID:                      c.String("key"),
   155  		ClientSecret:                  c.String("secret"),
   156  		OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
   157  		CustomURLMapping:              customURLMapping,
   158  		IconURL:                       c.String("icon-url"),
   159  		SkipLocalTwoFA:                c.Bool("skip-local-2fa"),
   160  		Scopes:                        c.StringSlice("scopes"),
   161  		RequiredClaimName:             c.String("required-claim-name"),
   162  		RequiredClaimValue:            c.String("required-claim-value"),
   163  		GroupClaimName:                c.String("group-claim-name"),
   164  		AdminGroup:                    c.String("admin-group"),
   165  		RestrictedGroup:               c.String("restricted-group"),
   166  		GroupTeamMap:                  c.String("group-team-map"),
   167  		GroupTeamMapRemoval:           c.Bool("group-team-map-removal"),
   168  	}
   169  }
   170  
   171  func runAddOauth(c *cli.Context) error {
   172  	ctx, cancel := installSignals()
   173  	defer cancel()
   174  
   175  	if err := initDB(ctx); err != nil {
   176  		return err
   177  	}
   178  
   179  	config := parseOAuth2Config(c)
   180  	if config.Provider == "openidConnect" {
   181  		discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
   182  		if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
   183  			return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
   184  		}
   185  	}
   186  
   187  	return auth_model.CreateSource(ctx, &auth_model.Source{
   188  		Type:     auth_model.OAuth2,
   189  		Name:     c.String("name"),
   190  		IsActive: true,
   191  		Cfg:      config,
   192  	})
   193  }
   194  
   195  func runUpdateOauth(c *cli.Context) error {
   196  	if !c.IsSet("id") {
   197  		return errors.New("--id flag is missing")
   198  	}
   199  
   200  	ctx, cancel := installSignals()
   201  	defer cancel()
   202  
   203  	if err := initDB(ctx); err != nil {
   204  		return err
   205  	}
   206  
   207  	source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	oAuth2Config := source.Cfg.(*oauth2.Source)
   213  
   214  	if c.IsSet("name") {
   215  		source.Name = c.String("name")
   216  	}
   217  
   218  	if c.IsSet("provider") {
   219  		oAuth2Config.Provider = c.String("provider")
   220  	}
   221  
   222  	if c.IsSet("key") {
   223  		oAuth2Config.ClientID = c.String("key")
   224  	}
   225  
   226  	if c.IsSet("secret") {
   227  		oAuth2Config.ClientSecret = c.String("secret")
   228  	}
   229  
   230  	if c.IsSet("auto-discover-url") {
   231  		oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url")
   232  	}
   233  
   234  	if c.IsSet("icon-url") {
   235  		oAuth2Config.IconURL = c.String("icon-url")
   236  	}
   237  
   238  	if c.IsSet("scopes") {
   239  		oAuth2Config.Scopes = c.StringSlice("scopes")
   240  	}
   241  
   242  	if c.IsSet("required-claim-name") {
   243  		oAuth2Config.RequiredClaimName = c.String("required-claim-name")
   244  	}
   245  	if c.IsSet("required-claim-value") {
   246  		oAuth2Config.RequiredClaimValue = c.String("required-claim-value")
   247  	}
   248  
   249  	if c.IsSet("group-claim-name") {
   250  		oAuth2Config.GroupClaimName = c.String("group-claim-name")
   251  	}
   252  	if c.IsSet("admin-group") {
   253  		oAuth2Config.AdminGroup = c.String("admin-group")
   254  	}
   255  	if c.IsSet("restricted-group") {
   256  		oAuth2Config.RestrictedGroup = c.String("restricted-group")
   257  	}
   258  	if c.IsSet("group-team-map") {
   259  		oAuth2Config.GroupTeamMap = c.String("group-team-map")
   260  	}
   261  	if c.IsSet("group-team-map-removal") {
   262  		oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
   263  	}
   264  
   265  	// update custom URL mapping
   266  	customURLMapping := &oauth2.CustomURLMapping{}
   267  
   268  	if oAuth2Config.CustomURLMapping != nil {
   269  		customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
   270  		customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
   271  		customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
   272  		customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
   273  		customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant
   274  	}
   275  	if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
   276  		customURLMapping.TokenURL = c.String("custom-token-url")
   277  	}
   278  
   279  	if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") {
   280  		customURLMapping.AuthURL = c.String("custom-auth-url")
   281  	}
   282  
   283  	if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") {
   284  		customURLMapping.ProfileURL = c.String("custom-profile-url")
   285  	}
   286  
   287  	if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") {
   288  		customURLMapping.EmailURL = c.String("custom-email-url")
   289  	}
   290  
   291  	if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") {
   292  		customURLMapping.Tenant = c.String("custom-tenant-id")
   293  	}
   294  
   295  	oAuth2Config.CustomURLMapping = customURLMapping
   296  	source.Cfg = oAuth2Config
   297  
   298  	return auth_model.UpdateSource(ctx, source)
   299  }