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 }