You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

admin_auth_oauth.go 8.0KB

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