From 87ebf3b1ba6f5c39296cfe1988c60ef6da11b50e Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 6 Nov 2026 07:21:19 +0000 Subject: [PATCH] feat(auth)!: remove support for obsolete OpenID 2.0 draft (#40231) Remove OpenID 2.0 authentication. The spec is an obsolete draft, major providers dropped it years ago, and the code keeps needing security fixes like https://github.com/go-gitea/gitea/pull/39642. OpenID Connect and OAuth2 are unaffected. Docs: https://gitea.com/gitea/docs/pulls/633. - The `[openid]` settings, OpenID sign-in, sign-up and account association are gone - A migration drops the `user_open_id` table with all user OpenID URIs - Accounts registered via OpenID have a random password and regain access via password reset Fixes: https://github.com/go-gitea/gitea/issues/1310 Fixes: https://github.com/go-gitea/gitea/issues/3521 --- assets/go-licenses.json | 5 - custom/conf/app.example.ini | 44 +- go.mod | 1 - go.sum | 16 - modelmigration/migrations.go | 1 + modelmigration/v29/v366.go | 14 + modelmigration/v29/v366_test.go | 33 ++ models/audit/action.go | 2 - models/fixtures/user_open_id.yml | 19 - models/user/openid.go | 127 ------ models/user/openid_test.go | 70 --- models/user/user.go | 27 -- models/user/user_test.go | 19 - modules/auth/openid/discovery_cache.go | 57 --- modules/auth/openid/discovery_cache_test.go | 49 -- modules/auth/openid/openid.go | 49 -- modules/auth/openid/openid_test.go | 29 -- modules/setting/service.go | 28 -- modules/web/middleware/data.go | 5 +- options/locale/locale_en-US.json | 21 - public/assets/img/openid-16x16.png | Bin 172 -> 0 bytes public/assets/img/svg/fontawesome-openid.svg | 1 - routers/web/auth/auth.go | 4 - routers/web/auth/auth_test.go | 43 +- routers/web/auth/linkaccount.go | 9 +- routers/web/auth/openid.go | 418 ------------------ routers/web/shared/user/header.go | 7 - routers/web/user/setting/security/openid.go | 180 -------- .../web/user/setting/security/openid_test.go | 113 ----- routers/web/user/setting/security/security.go | 12 - routers/web/web.go | 34 -- services/auth/session.go | 5 - services/auth/sspi.go | 2 - services/forms/user_form.go | 6 - services/forms/user_form_auth_openid.go | 27 -- services/user/delete.go | 1 - templates/admin/config.tmpl | 4 - templates/shared/user/profile_big_avatar.tmpl | 9 - .../user/auth/external_auth_methods.tmpl | 5 - templates/user/auth/signin_inner.tmpl | 2 +- templates/user/auth/signin_openid.tmpl | 50 --- templates/user/auth/signup_inner.tmpl | 2 +- .../user/auth/signup_openid_connect.tmpl | 35 -- templates/user/auth/signup_openid_navbar.tmpl | 12 - .../user/auth/signup_openid_register.tmpl | 36 -- templates/user/settings/security/openid.tmpl | 61 --- .../user/settings/security/security.tmpl | 3 - web_src/svg/fontawesome-openid.svg | 3 - 48 files changed, 59 insertions(+), 1641 deletions(-) create mode 100644 modelmigration/v29/v366.go create mode 100644 modelmigration/v29/v366_test.go delete mode 100644 models/fixtures/user_open_id.yml delete mode 100644 models/user/openid.go delete mode 100644 models/user/openid_test.go delete mode 100644 modules/auth/openid/discovery_cache.go delete mode 100644 modules/auth/openid/discovery_cache_test.go delete mode 100644 modules/auth/openid/openid.go delete mode 100644 modules/auth/openid/openid_test.go delete mode 100644 public/assets/img/openid-16x16.png delete mode 100644 public/assets/img/svg/fontawesome-openid.svg delete mode 100644 routers/web/auth/openid.go delete mode 100644 routers/web/user/setting/security/openid.go delete mode 100644 routers/web/user/setting/security/openid_test.go delete mode 100644 services/forms/user_form_auth_openid.go delete mode 100644 templates/user/auth/signin_openid.tmpl delete mode 100644 templates/user/auth/signup_openid_connect.tmpl delete mode 100644 templates/user/auth/signup_openid_navbar.tmpl delete mode 100644 templates/user/auth/signup_openid_register.tmpl delete mode 100644 templates/user/settings/security/openid.tmpl delete mode 100644 web_src/svg/fontawesome-openid.svg diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 1ca6797da00..004c9fe2564 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -954,11 +954,6 @@ "path": "github.com/x448/float16/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" }, - { - "name": "github.com/yohcop/openid-go", - "path": "github.com/yohcop/openid-go/LICENSE", - "licenseText": "Copyright 2015 Yohann Coppel\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" - }, { "name": "github.com/yuin/goldmark", "path": "github.com/yuin/goldmark/LICENSE", diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b093b88d9b9..6c7dce994a4 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1721,58 +1721,18 @@ LEVEL = Info ;; - manage_ssh_keys: a user cannot configure ssh keys ;; - manage_gpg_keys: a user cannot configure gpg keys ;; - manage_mfa: a user cannot configure mfa devices -;; - manage_credentials: a user cannot configure emails, passwords, or openid +;; - manage_credentials: a user cannot configure emails or passwords ;USER_DISABLED_FEATURES = ;; Comma separated list of disabled features ONLY if the user has an external login type (eg. LDAP, Oauth, etc.), could be "deletion", "manage_ssh_keys", "manage_gpg_keys", "manage_mfa", "manage_credentials". This setting is independent from `USER_DISABLED_FEATURES` and supplements its behavior. ;; - deletion: a user cannot delete their own account ;; - manage_ssh_keys: a user cannot configure ssh keys ;; - manage_gpg_keys: a user cannot configure gpg keys ;; - manage_mfa: a user cannot configure mfa devices -;; - manage_credentials: a user cannot configure emails, passwords, or openid +;; - manage_credentials: a user cannot configure emails or passwords ;; - change_username: a user cannot change their username ;; - change_full_name: a user cannot change their full name ;;EXTERNAL_USER_DISABLE_FEATURES = -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[openid] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; OpenID is an open, standard and decentralized authentication protocol. -;; Your identity is the address of a webpage you provide, which describes -;; how to prove you are in control of that page. -;; -;; For more info: https://en.wikipedia.org/wiki/OpenID -;; -;; Current implementation supports OpenID-2.0 -;; -;; Tested to work providers at the time of writing: -;; - Any GNUSocial node (your.hostname.tld/username) -;; - Any SimpleID provider (http://simpleid.koinic.net) -;; - http://openid.org.cn/ -;; - openid.stackexchange.com -;; - login.launchpad.net -;; - .livejournal.com -;; -;; Whether to allow sign-in via OpenID -;ENABLE_OPENID_SIGNIN = false -;; -;; Whether to allow registering via OpenID -;;ENABLE_OPENID_SIGNUP = false -;; -;; Allowed URI patterns (POSIX regexp). -;; Space separated. -;; Only these would be allowed if non-blank. -;; Example value: trusted.domain.org trusted.domain.net -;WHITELISTED_URIS = -;; -;; Forbidden URI patterns (POSIX regexp). -;; Space separated. -;; Only used if WHITELISTED_URIS is blank. -;; Example value: loadaverage.org/badguy stackexchange.com/.*spammer -;BLACKLISTED_URIS = - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[oauth2_client] diff --git a/go.mod b/go.mod index 0578e70d3f4..53c7418c810 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,6 @@ require ( github.com/urfave/cli-docs/v3 v3.1.0 github.com/urfave/cli/v3 v3.14.0 github.com/wneessen/go-mail v0.8.1 - github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.8.6 gitlab.com/gitlab-org/api/client-go/v3 v3.39.1 go.yaml.in/yaml/v4 v4.0.0 diff --git a/go.sum b/go.sum index 3b8c24c6ce0..ce8c9ce1e00 100644 --- a/go.sum +++ b/go.sum @@ -550,10 +550,7 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= -github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.8.6 h1:d0VcaP1sx9GkFVkoW+KtggpGi2KZ965i14b0+bDQST4= github.com/yuin/goldmark v1.8.6/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -592,7 +589,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= @@ -600,7 +596,6 @@ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aI golang.org/x/image v0.47.0 h1:za/8gVz++PPZqmZJBNSISICN5Rrj5zixP/8K++fgmqo= golang.org/x/image v0.47.0/go.mod h1:IkN5o4A7vq55vXN8FWjjnhg9Rs2GOtffqsSi9mWAKYE= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -609,8 +604,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.62.0 h1:18ELalfM5+XNRwzM2nYqXsZQ9ByS1uhj2O/U7+5jqRY= golang.org/x/net v0.62.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98= @@ -619,7 +612,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -633,24 +625,17 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM= golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc= golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s= golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= @@ -658,7 +643,6 @@ golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.52.0 h1:ryxg4U63oaUYk7uOLTF37n43f4qgtGvqV4Ioit1BaEs= golang.org/x/tools v0.52.0/go.mod h1:ItcP5UNaVGG+Yc4eIYmaFLNJ4soEopkx5Y2d4lcEurs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/modelmigration/migrations.go b/modelmigration/migrations.go index dd1fa3cab38..8e29a80d73c 100644 --- a/modelmigration/migrations.go +++ b/modelmigration/migrations.go @@ -442,6 +442,7 @@ func prepareMigrationTasks() []*migration { newMigration(363, "Add release_id to reaction table", v29.AddReleaseIDToReaction), newMigration(364, "Add new table project_workflow", v29.AddProjectWorkflow), newMigration(365, "Normalize legacy repository unit and login source JSON", v29.NormalizeLegacyConfigJSON), + newMigration(366, "Drop user_open_id table", v29.DropUserOpenIDTable), } return preparedMigrations } diff --git a/modelmigration/v29/v366.go b/modelmigration/v29/v366.go new file mode 100644 index 00000000000..f90d057d3e5 --- /dev/null +++ b/modelmigration/v29/v366.go @@ -0,0 +1,14 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v29 + +import ( + "context" + + "gitea.dev/modelmigration/base" +) + +func DropUserOpenIDTable(_ctx context.Context, x base.EngineMigration) error { + return x.DropTables("user_open_id") +} diff --git a/modelmigration/v29/v366_test.go b/modelmigration/v29/v366_test.go new file mode 100644 index 00000000000..a072470fc7f --- /dev/null +++ b/modelmigration/v29/v366_test.go @@ -0,0 +1,33 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v29 + +import ( + "testing" + + "gitea.dev/modelmigration/migrationtest" + + "github.com/stretchr/testify/require" +) + +func TestDropUserOpenIDTable(t *testing.T) { + type UserOpenID struct { + ID int64 `xorm:"pk autoincr"` + } + + x, cleanup := migrationtest.PrepareTestEnv(t, 0, new(UserOpenID)) + defer cleanup() + if x == nil || t.Failed() { + return + } + + exists, err := x.IsTableExist("user_open_id") + require.NoError(t, err) + require.True(t, exists) + require.NoError(t, DropUserOpenIDTable(t.Context(), x)) + exists, err = x.IsTableExist("user_open_id") + require.NoError(t, err) + require.False(t, exists) + require.NoError(t, DropUserOpenIDTable(t.Context(), x)) +} diff --git a/models/audit/action.go b/models/audit/action.go index 0fabc3f5d0b..96f23f56205 100644 --- a/models/audit/action.go +++ b/models/audit/action.go @@ -88,8 +88,6 @@ var ( UserWebAuthRemove = define("user:webauth:remove", "Removed WebAuthn key {credential} from user {scope}.") UserExternalLoginAdd = define("user:externallogin:add", "Added external login {external_id} for user {scope} using provider {provider}.") UserExternalLoginRemove = define("user:externallogin:remove", "Removed external login from authentication source {auth_source_id} for user {scope}.") - UserOpenIDAdd = define("user:openid:add", "Associated OpenID {openid} to user {scope}.") - UserOpenIDRemove = define("user:openid:remove", "Removed OpenID {openid} from user {scope}.") UserAccessTokenAdd = define("user:accesstoken:add", "Added access token {token} for user {scope} with scope {token_scope}.") UserAccessTokenRegenerate = define("user:accesstoken:regenerate", "Regenerated access token {token} of user {scope}.") UserAccessTokenRemove = define("user:accesstoken:remove", "Removed access token {token} from user {scope}.") diff --git a/models/fixtures/user_open_id.yml b/models/fixtures/user_open_id.yml deleted file mode 100644 index 72fe7e34b8c..00000000000 --- a/models/fixtures/user_open_id.yml +++ /dev/null @@ -1,19 +0,0 @@ -- - id: 1 - uid: 1 - uri: https://user1.domain1.tld/ - show: false - -- - id: 2 - uid: 1 - uri: http://user1.domain2.tld/ - show: true - -- - id: 3 - uid: 2 - uri: https://domain1.tld/user2/ - show: true - -# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly diff --git a/models/user/openid.go b/models/user/openid.go deleted file mode 100644 index 98d0128458f..00000000000 --- a/models/user/openid.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package user - -import ( - "context" - "fmt" - - "gitea.dev/models/db" - "gitea.dev/modules/util" - - "xorm.io/builder" -) - -// UserOpenID is the list of all OpenID identities of a user. -// Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here -type UserOpenID struct { //revive:disable-line:exported - ID int64 `xorm:"pk autoincr"` - UID int64 `xorm:"INDEX NOT NULL"` - URI string `xorm:"UNIQUE NOT NULL"` - Show bool `xorm:"DEFAULT false"` -} - -func init() { - db.RegisterModel(new(UserOpenID)) -} - -// GetUserOpenIDs returns all openid addresses that belongs to given user. -func GetUserOpenIDs(ctx context.Context, uid int64) ([]*UserOpenID, error) { - openids := make([]*UserOpenID, 0, 5) - if err := db.GetEngine(ctx). - Where("uid=?", uid). - Asc("id"). - Find(&openids); err != nil { - return nil, err - } - - return openids, nil -} - -// isOpenIDUsed returns true if the openid has been used. -func isOpenIDUsed(ctx context.Context, uri string) (bool, error) { - if len(uri) == 0 { - return true, nil - } - - return db.Exist[UserOpenID](ctx, builder.Eq{"uri": uri}) -} - -// ErrOpenIDAlreadyUsed represents a "OpenIDAlreadyUsed" kind of error. -type ErrOpenIDAlreadyUsed struct { - OpenID string -} - -// IsErrOpenIDAlreadyUsed checks if an error is a ErrOpenIDAlreadyUsed. -func IsErrOpenIDAlreadyUsed(err error) bool { - _, ok := err.(ErrOpenIDAlreadyUsed) - return ok -} - -func (err ErrOpenIDAlreadyUsed) Error() string { - return fmt.Sprintf("OpenID already in use [oid: %s]", err.OpenID) -} - -func (err ErrOpenIDAlreadyUsed) Unwrap() error { - return util.ErrAlreadyExist -} - -// AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. -// NOTE: make sure openid.URI is normalized already -func AddUserOpenID(ctx context.Context, openid *UserOpenID) error { - used, err := isOpenIDUsed(ctx, openid.URI) - if err != nil { - return err - } else if used { - return ErrOpenIDAlreadyUsed{openid.URI} - } - - return db.Insert(ctx, openid) -} - -// GetUserOpenIDByID returns the OpenID with the given ID owned by uid. -func GetUserOpenIDByID(ctx context.Context, id, uid int64) (*UserOpenID, error) { - oid, has, err := db.Get[UserOpenID](ctx, builder.Eq{"id": id, "uid": uid}) - if err != nil { - return nil, err - } else if !has { - return nil, util.NewNotExistErrorf("OpenID is unknown") - } - return oid, nil -} - -// DeleteUserOpenID deletes an openid address of given user. -func DeleteUserOpenID(ctx context.Context, openid *UserOpenID) (err error) { - var deleted int64 - // ask to check UID - address := UserOpenID{ - UID: openid.UID, - } - if openid.ID > 0 { - deleted, err = db.GetEngine(ctx).ID(openid.ID).Delete(&address) - } else { - deleted, err = db.GetEngine(ctx). - Where("openid=?", openid.URI). - Delete(&address) - } - - if err != nil { - return err - } else if deleted != 1 { - return util.NewNotExistErrorf("OpenID is unknown") - } - return nil -} - -// ToggleUserOpenIDVisibility toggles visibility of an openid address of given user. -func ToggleUserOpenIDVisibility(ctx context.Context, id int64, user *User) error { - affected, err := db.GetEngine(ctx).Exec("update `user_open_id` set `show` = not `show` where `id` = ? AND uid = ?", id, user.ID) - if err != nil { - return err - } - if n, _ := affected.RowsAffected(); n != 1 { - return util.NewNotExistErrorf("OpenID is unknown") - } - return nil -} diff --git a/models/user/openid_test.go b/models/user/openid_test.go deleted file mode 100644 index fcb2752b562..00000000000 --- a/models/user/openid_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package user_test - -import ( - "testing" - - "gitea.dev/models/unittest" - user_model "gitea.dev/models/user" - "gitea.dev/modules/util" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestUserOpenIDs(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - t.Run("GetUserOpenIDs", func(t *testing.T) { - oids, err := user_model.GetUserOpenIDs(t.Context(), int64(1)) - if assert.NoError(t, err) && assert.Len(t, oids, 2) { - assert.Equal(t, "https://user1.domain1.tld/", oids[0].URI) - assert.False(t, oids[0].Show) - assert.Equal(t, "http://user1.domain2.tld/", oids[1].URI) - assert.True(t, oids[1].Show) - } - - oids, err = user_model.GetUserOpenIDs(t.Context(), int64(2)) - if assert.NoError(t, err) && assert.Len(t, oids, 1) { - assert.Equal(t, "https://domain1.tld/user2/", oids[0].URI) - assert.True(t, oids[0].Show) - } - }) - - t.Run("ToggleUserOpenIDVisibilityRequiresOwnership", func(t *testing.T) { - unauthorizedUser, err := user_model.GetUserByID(t.Context(), int64(2)) - require.NoError(t, err) - - err = user_model.ToggleUserOpenIDVisibility(t.Context(), int64(1), unauthorizedUser) - require.Error(t, err) - assert.ErrorIs(t, err, util.ErrNotExist) - }) - - t.Run("ToggleUserOpenIDVisibility", func(t *testing.T) { - user, err := user_model.GetUserByID(t.Context(), int64(2)) - require.NoError(t, err) - oids, err := user_model.GetUserOpenIDs(t.Context(), int64(2)) - require.NoError(t, err) - require.Len(t, oids, 1) - assert.True(t, oids[0].Show) - - err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID, user) - require.NoError(t, err) - - oids, err = user_model.GetUserOpenIDs(t.Context(), int64(2)) - require.NoError(t, err) - require.Len(t, oids, 1) - - assert.False(t, oids[0].Show) - err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID, user) - require.NoError(t, err) - - oids, err = user_model.GetUserOpenIDs(t.Context(), int64(2)) - require.NoError(t, err) - if assert.Len(t, oids, 1) { - assert.True(t, oids[0].Show) - } - }) -} diff --git a/models/user/user.go b/models/user/user.go index 3bbf52b082c..eddcf69738a 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -22,7 +22,6 @@ import ( "gitea.dev/models/auth" "gitea.dev/models/db" - "gitea.dev/modules/auth/openid" "gitea.dev/modules/auth/password/hash" "gitea.dev/modules/base" "gitea.dev/modules/container" @@ -1441,32 +1440,6 @@ func GetIndividualUserByLoginSource(ctx context.Context, loginType auth.Type, lo return user, has, err } -// GetUserByOpenID returns the user object by given OpenID if exists. -func GetUserByOpenID(ctx context.Context, uri string) (*User, error) { - if len(uri) == 0 { - return nil, ErrUserNotExist{Name: uri} - } - - uri, err := openid.Normalize(uri) - if err != nil { - return nil, err - } - - log.Trace("Normalized OpenID URI: " + uri) - - // Otherwise, check in openid table - oid := &UserOpenID{} - has, err := db.GetEngine(ctx).Where("uri=?", uri).Get(oid) - if err != nil { - return nil, err - } - if has { - return GetUserByID(ctx, oid.UID) - } - - return nil, ErrUserNotExist{Name: uri} -} - // GetAdminUser returns the first administrator func GetAdminUser(ctx context.Context) (*User, error) { var admin User diff --git a/models/user/user_test.go b/models/user/user_test.go index c70879a0679..e3374e0b23a 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -417,25 +417,6 @@ func TestNewUserRedirect(t *testing.T) { } } -func TestGetUserByOpenID(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - _, err := user_model.GetUserByOpenID(t.Context(), "https://unknown") - if assert.Error(t, err) { - assert.True(t, user_model.IsErrUserNotExist(err)) - } - - user, err := user_model.GetUserByOpenID(t.Context(), "https://user1.domain1.tld") - if assert.NoError(t, err) { - assert.Equal(t, int64(1), user.ID) - } - - user, err = user_model.GetUserByOpenID(t.Context(), "https://domain1.tld/user2/") - if assert.NoError(t, err) { - assert.Equal(t, int64(2), user.ID) - } -} - func TestFollowUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/modules/auth/openid/discovery_cache.go b/modules/auth/openid/discovery_cache.go deleted file mode 100644 index 3a8d119bdd1..00000000000 --- a/modules/auth/openid/discovery_cache.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package openid - -import ( - "sync" - "time" - - "github.com/yohcop/openid-go" -) - -type timedDiscoveredInfo struct { - info openid.DiscoveredInfo - time time.Time -} - -type timedDiscoveryCache struct { - cache map[string]timedDiscoveredInfo - ttl time.Duration - mutex *sync.Mutex -} - -func newTimedDiscoveryCache(ttl time.Duration) *timedDiscoveryCache { - return &timedDiscoveryCache{cache: map[string]timedDiscoveredInfo{}, ttl: ttl, mutex: &sync.Mutex{}} -} - -func (s *timedDiscoveryCache) Put(id string, info openid.DiscoveredInfo) { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.cache[id] = timedDiscoveredInfo{info: info, time: time.Now()} -} - -// Delete timed-out cache entries -func (s *timedDiscoveryCache) cleanTimedOut() { - now := time.Now() - for k, e := range s.cache { - diff := now.Sub(e.time) - if diff > s.ttl { - delete(s.cache, k) - } - } -} - -func (s *timedDiscoveryCache) Get(id string) openid.DiscoveredInfo { - s.mutex.Lock() - defer s.mutex.Unlock() - - // Delete old cached while we are at it. - s.cleanTimedOut() - - if info, has := s.cache[id]; has { - return info.info - } - return nil -} diff --git a/modules/auth/openid/discovery_cache_test.go b/modules/auth/openid/discovery_cache_test.go deleted file mode 100644 index f3d7dd226ef..00000000000 --- a/modules/auth/openid/discovery_cache_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package openid - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type testDiscoveredInfo struct{} - -func (s *testDiscoveredInfo) ClaimedID() string { - return "claimedID" -} - -func (s *testDiscoveredInfo) OpEndpoint() string { - return "opEndpoint" -} - -func (s *testDiscoveredInfo) OpLocalID() string { - return "opLocalID" -} - -func TestTimedDiscoveryCache(t *testing.T) { - ttl := 50 * time.Millisecond - dc := newTimedDiscoveryCache(ttl) - - // Put some initial values - dc.Put("foo", &testDiscoveredInfo{}) // openid.opEndpoint: "a", openid.opLocalID: "b", openid.claimedID: "c"}) - - // Make sure we can retrieve them - di := dc.Get("foo") - require.NotNil(t, di) - assert.Equal(t, "opEndpoint", di.OpEndpoint()) - assert.Equal(t, "opLocalID", di.OpLocalID()) - assert.Equal(t, "claimedID", di.ClaimedID()) - - // Attempt to get a non-existent value - assert.Nil(t, dc.Get("bar")) - - // Sleep for a while and try to retrieve again - time.Sleep(ttl * 3 / 2) - - assert.Nil(t, dc.Get("foo")) -} diff --git a/modules/auth/openid/openid.go b/modules/auth/openid/openid.go deleted file mode 100644 index b2db1d3be95..00000000000 --- a/modules/auth/openid/openid.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package openid - -import ( - "net/http" - "sync" - "time" - - "gitea.dev/modules/egress" - - "github.com/yohcop/openid-go" -) - -// For the demo, we use in-memory infinite storage nonce and discovery -// cache. In your app, do not use this as it will eat up memory and -// never -// free it. Use your own implementation, on a better database system. -// If you have multiple servers for example, you may need to share at -// least -// the nonceStore between them. -var ( - nonceStore = openid.NewSimpleNonceStore() - discoveryCache = newTimedDiscoveryCache(24 * time.Hour) - - // openIDInstance keeps user-supplied OpenID identifiers within [security] ALLOWED_HOST_LIST - openIDInstance = sync.OnceValue(func() *openid.OpenID { - return openid.NewOpenID(&http.Client{ - Timeout: 30 * time.Second, - Transport: egress.NewSecurityPolicy("openid").NewHTTPTransport(), - }) - }) -) - -// Verify handles response from OpenID provider -func Verify(fullURL string) (id string, err error) { - return openIDInstance().Verify(fullURL, discoveryCache, nonceStore) -} - -// Normalize normalizes an OpenID URI -func Normalize(url string) (id string, err error) { - return openid.Normalize(url) -} - -// RedirectURL redirects browser -func RedirectURL(id, callbackURL, realm string) (string, error) { - return openIDInstance().RedirectURL(id, callbackURL, realm) -} diff --git a/modules/auth/openid/openid_test.go b/modules/auth/openid/openid_test.go deleted file mode 100644 index 66e3e10495a..00000000000 --- a/modules/auth/openid/openid_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2026 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package openid - -import ( - "net/http" - "net/http/httptest" - "sync/atomic" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestOpenIDDiscoveryBlocksInternalHost(t *testing.T) { - var reached atomic.Bool - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - reached.Store(true) - w.WriteHeader(http.StatusOK) - })) - defer srv.Close() - - // RedirectURL performs server-side discovery of the identifier URL; a loopback URL - // must be refused at dial time instead of reaching the internal server - _, err := RedirectURL(srv.URL, "http://example.com/callback", "http://example.com/") - require.Error(t, err) - assert.False(t, reached.Load(), "OpenID discovery must not reach an internal/loopback host") -} diff --git a/modules/setting/service.go b/modules/setting/service.go index 2ffcd895f3c..79149b51c85 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -4,7 +4,6 @@ package setting import ( - "regexp" "runtime" "strings" "time" @@ -82,12 +81,6 @@ var Service = struct { UserDeleteWithCommentsMaxTime time.Duration ValidSiteURLSchemes []string - // OpenID settings - EnableOpenIDSignIn bool - EnableOpenIDSignUp bool - OpenIDWhitelist []*regexp.Regexp - OpenIDBlacklist []*regexp.Regexp - // Explore page settings Explore struct { RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` @@ -257,30 +250,9 @@ func loadServiceFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "service.explore", &Service.Explore) - loadOpenIDSetting(rootCfg) loadQosSetting(rootCfg) } -func loadOpenIDSetting(rootCfg ConfigProvider) { - sec := rootCfg.Section("openid") - Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(false) - Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(false) - pats := sec.Key("WHITELISTED_URIS").Strings(" ") - if len(pats) != 0 { - Service.OpenIDWhitelist = make([]*regexp.Regexp, len(pats)) - for i, p := range pats { - Service.OpenIDWhitelist[i] = regexp.MustCompilePOSIX(p) - } - } - pats = sec.Key("BLACKLISTED_URIS").Strings(" ") - if len(pats) != 0 { - Service.OpenIDBlacklist = make([]*regexp.Regexp, len(pats)) - for i, p := range pats { - Service.OpenIDBlacklist[i] = regexp.MustCompilePOSIX(p) - } - } -} - func loadQosSetting(rootCfg ConfigProvider) { sec := rootCfg.Section("qos") Service.QoS.Enabled = sec.Key("ENABLED").MustBool(false) diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index f7ea662cdfc..169911d558d 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -36,9 +36,8 @@ func CommonTemplateContextData() reqctx.ContextData { "ShowFooterVersion": setting.Other.ShowFooterVersion, "DisableDownloadSourceArchives": setting.Repository.DisableDownloadSourceArchives, - "EnableSwagger": setting.API.EnableSwagger, - "EnableOpenIDSignIn": setting.Service.EnableOpenIDSignIn, - "PageStartTime": time.Now(), + "EnableSwagger": setting.API.EnableSwagger, + "PageStartTime": time.Now(), "RunModeIsProd": setting.IsProd, "ViteModeIsDev": public.IsViteDevMode(), diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 2a242ac870d..acc88e830b9 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -409,7 +409,6 @@ "auth.twofa_scratch_token_incorrect": "Your scratch code is incorrect.", "auth.twofa_required": "You must set up two-factor authentication to get access to repositories, or try to log in again.", "auth.login_userpass": "Sign In", - "auth.login_openid": "OpenID", "auth.oauth_signup_tab": "Register New Account", "auth.oauth_signup_title": "Complete New Account", "auth.oauth_signup_submit": "Complete Account", @@ -420,12 +419,6 @@ "auth.oauth.signin.error.access_denied": "The authorization request was denied.", "auth.oauth.signin.error.temporarily_unavailable": "Authorization failed because the authentication server is temporarily unavailable. Please try again later.", "auth.oauth_callback_unable_auto_reg": "Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically. Please create or link to an account, or contact the site administrator.", - "auth.openid_connect_submit": "Connect", - "auth.openid_connect_title": "Connect to an existing account", - "auth.openid_connect_desc": "The chosen OpenID URI is unknown. Associate it with a new account here.", - "auth.openid_register_title": "Create new account", - "auth.openid_register_desc": "The chosen OpenID URI is unknown. Associate it with a new account here.", - "auth.openid_signin_desc": "Enter your OpenID URI. For example: alice.openid.example.org or https://openid.example.org/alice.", "auth.disable_forgot_password_mail": "Account recovery is disabled because no email address is set up. Please contact your site administrator.", "auth.disable_forgot_password_mail_admin": "Account recovery is only available when an email address is set up.", "auth.email_domain_blacklisted": "You cannot register with your email address.", @@ -443,7 +436,6 @@ "auth.password_pwned_err": "Could not complete request to HaveIBeenPwned", "auth.last_admin": "You cannot remove the last admin. There must be at least one admin.", "auth.signin_passkey": "Sign in with a passkey", - "auth.back_to_sign_in": "Back to Sign In", "mail.view_it_on": "View it on %s", "mail.reply": "or reply to this email directly", "mail.reply_directly": "Reply to this email directly", @@ -563,7 +555,6 @@ "form.email_been_used": "The email address is already used.", "form.email_invalid": "The email address is invalid.", "form.email_domain_is_not_allowed": "The domain of user email address %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST. Please ensure your operation is expected.", - "form.openid_been_used": "The OpenID address \"%s\" is already used.", "form.username_password_incorrect": "Username or password is incorrect.", "form.password_complexity": "Password does not pass complexity requirements:", "form.password_lowercase_one": "At least one lowercase character", @@ -717,7 +708,6 @@ "settings.emails": "Email Addresses", "settings.manage_emails": "Manage Email Addresses", "settings.manage_themes": "Select default theme", - "settings.manage_openid": "Manage OpenID Addresses", "settings.email_desc": "Your primary email address will be used for notifications, password recovery and, provided that it is not hidden, web-based Git operations.", "settings.theme_desc": "This will be your default theme across the site.", "settings.theme_colorblindness_help": "Color blindness Theme Support", @@ -735,21 +725,14 @@ "settings.email_deletion_success": "The email address has been removed.", "settings.theme_update_success": "Your theme was updated.", "settings.theme_update_error": "The selected theme does not exist.", - "settings.openid_deletion": "Remove OpenID Address", - "settings.openid_deletion_desc": "Removing this OpenID address from your account will prevent you from signing in with it. Continue?", - "settings.openid_deletion_success": "The OpenID address has been removed.", "settings.add_new_email": "Add New Email Address", - "settings.add_new_openid": "Add New OpenID URI", "settings.add_email": "Add Email Address", - "settings.add_openid": "Add OpenID URI", "settings.add_email_confirmation_sent": "A confirmation email has been sent to \"%s\". Please check your inbox within the next %s to confirm your email address.", "settings.email_primary_not_found": "The selected email address could not be found.", "settings.add_email_success": "The new email address has been added.", "settings.email_preference_set_success": "Email preference has been set successfully.", - "settings.add_openid_success": "The new OpenID address has been added.", "settings.keep_email_private": "Hide Email Address", "settings.keep_email_private_popup": "This will hide your email address from your profile, as well as when you make a pull request or edit a file using the web interface. Pushed commits will not be modified. Use %s in commits to associate them with your account.", - "settings.openid_desc": "OpenID lets you delegate authentication to an external provider.", "settings.manage_ssh_keys": "Manage SSH Keys", "settings.manage_ssh_principals": "Manage SSH Certificate Principals", "settings.manage_gpg_keys": "Manage GPG Keys", @@ -818,8 +801,6 @@ "settings.key_state_desc": "This key has been used in the last 7 days", "settings.token_state_desc": "This token has been used in the last 7 days", "settings.principal_state_desc": "This principal has been used in the last 7 days", - "settings.show_openid": "Show on profile", - "settings.hide_openid": "Hide from profile", "settings.ssh_disabled": "SSH Disabled", "settings.ssh_signonly": "SSH is currently disabled so these keys are only used for commit signature verification.", "settings.ssh_externally_managed": "This SSH key is externally managed for this user", @@ -3358,8 +3339,6 @@ "admin.config.disable_register": "Disable Self-Registration", "admin.config.allow_only_internal_registration": "Allow Registration Only Through Gitea itself", "admin.config.allow_only_external_registration": "Allow Registration Only Through External Services", - "admin.config.enable_openid_signup": "Enable OpenID Self-Registration", - "admin.config.enable_openid_signin": "Enable OpenID Sign-In", "admin.config.show_registration_button": "Show Register Button", "admin.config.require_sign_in_view": "Require Sign-In to View Pages", "admin.config.mail_notify": "Enable Email Notifications", diff --git a/public/assets/img/openid-16x16.png b/public/assets/img/openid-16x16.png deleted file mode 100644 index ee1b00e147f4ec49b3d843114a966a787d762ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDU{rmsVpUVq>OqP7~1PK4;$SYd5YQX=yC9k;t U1h}j_1T>n#)78&qol`;+0Iq90p8x;= diff --git a/public/assets/img/svg/fontawesome-openid.svg b/public/assets/img/svg/fontawesome-openid.svg deleted file mode 100644 index f806899bde9..00000000000 --- a/public/assets/img/svg/fontawesome-openid.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index f2ff5fcc358..288a2c5b77d 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -56,9 +56,6 @@ type CommonAuthOptions struct { func prepareCommonAuthPageData(ctx *context.Context, opt CommonAuthOptions) { ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth - - // for OpenID Connect - ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration if opt.EnableCaptcha { @@ -230,7 +227,6 @@ func performAutoLoginOAuth2(ctx *context.Context, data *preparedSignInData) bool // If only 1 OAuth provider is present and other login methods are disabled, redirect to the OAuth provider. onlySingleOAuth2 := len(data.oauth2Providers) == 1 && !setting.Service.EnablePasswordSignInForm && - !setting.Service.EnableOpenIDSignIn && !setting.Service.EnablePasskeyAuth && !data.enableSSPI diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go index 26e6df153dc..e987fd7bc31 100644 --- a/routers/web/auth/auth_test.go +++ b/routers/web/auth/auth_test.go @@ -17,11 +17,9 @@ import ( "gitea.dev/modules/setting" "gitea.dev/modules/test" "gitea.dev/modules/util" - "gitea.dev/modules/web" auth_service "gitea.dev/services/auth" "gitea.dev/services/auth/source/oauth2" "gitea.dev/services/contexttest" - "gitea.dev/services/forms" "github.com/markbates/goth" "github.com/markbates/goth/gothic" @@ -103,10 +101,8 @@ func TestWebAuthOAuth2(t *testing.T) { t.Run("RedirectSingleProvider", func(t *testing.T) { enablePassword := &setting.Service.EnablePasswordSignInForm - enableOpenID := &setting.Service.EnableOpenIDSignIn enablePasskey := &setting.Service.EnablePasskeyAuth defer test.MockVariableValue(enablePassword, false)() - defer test.MockVariableValue(enableOpenID, false)() defer test.MockVariableValue(enablePasskey, false)() testSignIn := func(t *testing.T, link string, expectedCode int, expectedRedirect string) { @@ -120,14 +116,12 @@ func TestWebAuthOAuth2(t *testing.T) { testSignIn(t, "/user/login", http.StatusSeeOther, "/user/oauth2/dummy+auth%27s%20source") testSignIn(t, "/user/login?redirect_to=/", http.StatusSeeOther, "/user/oauth2/dummy+auth%27s%20source?redirect_to=%2F") - *enablePassword, *enableOpenID, *enablePasskey = true, false, false + *enablePassword, *enablePasskey = true, false testSignIn(t, "/user/login", http.StatusOK, "") - *enablePassword, *enableOpenID, *enablePasskey = false, true, false - testSignIn(t, "/user/login", http.StatusOK, "") - *enablePassword, *enableOpenID, *enablePasskey = false, false, true + *enablePassword, *enablePasskey = false, true testSignIn(t, "/user/login", http.StatusOK, "") - *enablePassword, *enableOpenID, *enablePasskey = false, false, false + *enablePassword, *enablePasskey = false, false addOAuth2Source(t, "dummy-auth-source-2", oauth2.Source{}) testSignIn(t, "/user/login", http.StatusOK, "") }) @@ -187,37 +181,6 @@ func TestWebAuthOAuth2(t *testing.T) { }) } -func TestOpenIDRequireTwoFactor(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid-openid")} - - user32 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 32}) // has a webauthn credential - ctx, resp := contexttest.MockContext(t, "/user/openid/connect", mockOpt) - openIDRequireTwoFactor(ctx, user32, false, "https://example.com/id") - assert.Equal(t, "/user/webauthn", test.RedirectURL(resp)) - unittest.AssertNotExistsBean(t, &user_model.UserOpenID{UID: user32.ID}) // not attached before the key answered - - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - ctx, _ = contexttest.MockContext(t, "/user/openid/connect", mockOpt) - openIDRequireTwoFactor(ctx, user2, false, "https://example.com/id") - assert.False(t, ctx.Written()) -} - -func TestRegisterOpenIDPostRejectsWrongCaptcha(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - defer test.MockVariableValue(&setting.Service.EnableCaptcha, true)() - defer test.MockVariableValue(&setting.Service.CaptchaType, setting.ImageCaptcha)() - sess := session.NewMockMemStore("dummy-sid-openid-register") - require.NoError(t, sess.Set("openid_verified_uri", "https://example.com/openid")) - - ctx, _ := contexttest.MockContext(t, "POST /user/openid/register", contexttest.MockContextOption{SessionStore: sess}) - contexttest.MockRequestPostForm(ctx.Req, url.Values{"captcha_id": {"unknown"}, "captcha": {"000000"}}) - web.SetForm(ctx, &forms.SignUpOpenIDForm{UserName: "openid-captcha-user", Email: "openid-captcha-user@example.com"}) - RegisterOpenIDPost(ctx) - assert.Equal(t, true, ctx.Data["Err_Captcha"]) - unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "openid-captcha-user"}) -} - func TestAutoSignInStaleCookie(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) at, token, err := auth_service.CreateAuthTokenForUserID(t.Context(), 2) diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 7970bf92a0a..cc8e44a081e 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -263,15 +263,10 @@ func LinkAccountPostRegister(ctx *context.Context) { } func completePendingLinks(ctx *context.Context, user *user_model.User) error { - if ctx.Session.Get("linkAccount") != nil { - if err := linkAccountFromContext(ctx, user); err != nil { - return err - } + if ctx.Session.Get("linkAccount") == nil { + return nil } - return openIDConnectFromContext(ctx, user) -} -func linkAccountFromContext(ctx *context.Context, user *user_model.User) error { linkAccountData := oauth2GetLinkAccountData(ctx) if linkAccountData == nil { return errors.New("not in LinkAccount session") diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go deleted file mode 100644 index d608128f87b..00000000000 --- a/routers/web/auth/openid.go +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package auth - -import ( - "errors" - "net/http" - "net/url" - - auth_model "gitea.dev/models/auth" - user_model "gitea.dev/models/user" - "gitea.dev/modules/auth/openid" - "gitea.dev/modules/log" - "gitea.dev/modules/setting" - "gitea.dev/modules/templates" - "gitea.dev/modules/util" - "gitea.dev/modules/web" - "gitea.dev/services/auth" - "gitea.dev/services/context" - "gitea.dev/services/forms" -) - -const ( - tplSignInOpenID templates.TplName = "user/auth/signin_openid" - tplConnectOID templates.TplName = "user/auth/signup_openid_connect" - tplSignUpOID templates.TplName = "user/auth/signup_openid_register" -) - -// the OpenID is attached only after the second factor passed, so a stolen password cannot leave one behind -func openIDRequireTwoFactor(ctx *context.Context, u *user_model.User, remember bool, pendingURI string) { - hasTwoFactor, err := auth_model.HasTwoFactorOrWebAuthn(ctx, u.ID) - if err != nil { - ctx.ServerError("HasTwoFactorOrWebAuthn", err) - return - } - if !hasTwoFactor { - return - } - handleTwoFactorRequired(ctx, u, remember, map[string]any{"openidPendingURI": pendingURI}) -} - -func openIDConnectFromContext(ctx *context.Context, u *user_model.User) error { - uri, _ := ctx.Session.Get("openidPendingURI").(string) - if uri == "" { - return nil - } - if err := ctx.Session.Delete("openidPendingURI"); err != nil { - return err - } - if err := user_model.AddUserOpenID(ctx, &user_model.UserOpenID{UID: u.ID, URI: uri}); err != nil { - if !user_model.IsErrOpenIDAlreadyUsed(err) { - return err - } - ctx.Flash.Error(ctx.Tr("form.openid_been_used", uri)) - } - return nil -} - -// SignInOpenID render sign in page -func SignInOpenID(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("sign_in") - - if ctx.FormString("openid.return_to") != "" { - signInOpenIDVerify(ctx) - return - } - - if performAutoLogin(ctx) { - return - } - - ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsLoginOpenID"] = true - ctx.HTML(http.StatusOK, tplSignInOpenID) -} - -// Check if the given OpenID URI is allowed by blacklist/whitelist -func allowedOpenIDURI(uri string) (err error) { - // In case a Whitelist is present, URI must be in it - // in order to be accepted - if len(setting.Service.OpenIDWhitelist) != 0 { - for _, pat := range setting.Service.OpenIDWhitelist { - if pat.MatchString(uri) { - return nil // pass - } - } - // must match one of this or be refused - return errors.New("URI not allowed by whitelist") - } - - // A blacklist match expliclty forbids - for _, pat := range setting.Service.OpenIDBlacklist { - if pat.MatchString(uri) { - return errors.New("URI forbidden by blacklist") - } - } - - return nil -} - -// SignInOpenIDPost response for openid sign in request -func SignInOpenIDPost(ctx *context.Context) { - form := web.GetForm[*forms.SignInOpenIDForm](ctx) - ctx.Data["Title"] = ctx.Tr("sign_in") - ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsLoginOpenID"] = true - - if ctx.HasError() { - ctx.HTML(http.StatusOK, tplSignInOpenID) - return - } - - id, err := openid.Normalize(form.Openid) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &form) - return - } - form.Openid = id - - log.Trace("OpenID uri: " + id) - - err = allowedOpenIDURI(id) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &form) - return - } - - redirectTo := setting.AppURL + "user/login/openid" - url, err := openid.RedirectURL(id, redirectTo, setting.AppURL) - if err != nil { - log.Error("Error in OpenID redirect URL: %s, %v", redirectTo, err.Error()) - ctx.RenderWithErrDeprecated("Unable to find OpenID provider in "+redirectTo, tplSignInOpenID, &form) - return - } - - // Request optional nickname and email info - // NOTE: change to `openid.sreg.required` to require it - url += "&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1" - url += "&openid.sreg.optional=nickname%2Cemail" - - log.Trace("Form-passed openid-remember: %t", form.Remember) - - if err := ctx.Session.Set("openid_signin_remember", form.Remember); err != nil { - log.Error("SignInOpenIDPost: Could not set openid_signin_remember in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("SignInOpenIDPost: Unable to save changes to the session: %v", err) - } - - ctx.Redirect(url) -} - -// signInOpenIDVerify handles response from OpenID provider -func signInOpenIDVerify(ctx *context.Context) { - log.Trace("Incoming call to: %s", ctx.Req.URL.String()) - - fullURL := setting.AppURL + ctx.Req.URL.String()[1:] - log.Trace("Full URL: %s", fullURL) - - id, err := openid.Verify(fullURL) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - - log.Trace("Verified ID: %s", id) - - /* Now we should seek for the user and log him in, or prompt - * to register if not found */ - - u, err := user_model.GetUserByOpenID(ctx, id) - if err != nil { - if !user_model.IsErrUserNotExist(err) { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - log.Error("signInOpenIDVerify: %v", err) - } - if u != nil { - log.Trace("User exists, logging in") - remember, _ := ctx.Session.Get("openid_signin_remember").(bool) - log.Trace("Session stored openid-remember: %t", remember) - openIDRequireTwoFactor(ctx, u, remember, "") - if ctx.Written() { - return - } - handleSignIn(ctx, u, remember) - return - } - - log.Trace("User with openid: %s does not exist, should connect or register", id) - - parsedURL, err := url.Parse(fullURL) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - values, err := url.ParseQuery(parsedURL.RawQuery) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - email := values.Get("openid.sreg.email") - nickname := values.Get("openid.sreg.nickname") - - log.Trace("User has email=%s and nickname=%s", email, nickname) - - if email != "" { - u, err = user_model.GetUserByEmail(ctx, email) - if err != nil { - if !user_model.IsErrUserNotExist(err) { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - log.Error("signInOpenIDVerify: %v", err) - } - if u != nil { - log.Trace("Local user %s has OpenID provided email %s", u.LowerName, email) - } - } - - if u == nil && nickname != "" { - u, _ = user_model.GetUserByName(ctx, nickname) - if err != nil { - if !user_model.IsErrUserNotExist(err) { - ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ - Openid: id, - }) - return - } - } - if u != nil { - log.Trace("Local user %s has OpenID provided nickname %s", u.LowerName, nickname) - } - } - - if u != nil { - nickname = u.LowerName - } - if err := regenerateSession(ctx, map[string]any{ - "openid_verified_uri": id, - "openid_determined_email": email, - "openid_determined_username": nickname, - }); err != nil { - ctx.ServerError("updateSession", err) - return - } - - if u != nil || !setting.Service.EnableOpenIDSignUp || setting.Service.AllowOnlyInternalRegistration { - ctx.Redirect(setting.AppSubURL + "/user/openid/connect") - } else { - ctx.Redirect(setting.AppSubURL + "/user/openid/register") - } -} - -func prepareConnectOpenIDPageData(ctx *context.Context) (oid string) { - oid, _ = ctx.Session.Get("openid_verified_uri").(string) - if oid == "" { - ctx.Redirect(setting.AppSubURL + "/user/login/openid") - return "" - } - ctx.Data["Title"] = "OpenID connect" - ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsOpenIDConnect"] = true - ctx.Data["OpenID"] = oid - prepareCommonAuthPageData(ctx, CommonAuthOptions{EnableCaptcha: false}) - return oid -} - -// ConnectOpenID shows a form to connect an OpenID URI to an existing account -func ConnectOpenID(ctx *context.Context) { - oid := prepareConnectOpenIDPageData(ctx) - if oid == "" { - return - } - userName, _ := ctx.Session.Get("openid_determined_username").(string) - if userName != "" { - ctx.Data["user_name"] = userName - } - ctx.HTML(http.StatusOK, tplConnectOID) -} - -// ConnectOpenIDPost handles submission of a form to connect an OpenID URI to an existing account -func ConnectOpenIDPost(ctx *context.Context) { - form := web.GetForm[*forms.ConnectOpenIDForm](ctx) - oid := prepareConnectOpenIDPageData(ctx) - if oid == "" { - return - } - - u, _, err := auth.UserSignIn(ctx, form.UserName, form.Password) - if err != nil { - handleSignInError(ctx, form.UserName, &form, tplConnectOID, "ConnectOpenIDPost", err) - return - } - - remember, _ := ctx.Session.Get("openid_signin_remember").(bool) - openIDRequireTwoFactor(ctx, u, remember, oid) - if ctx.Written() { - return - } - - userOID := &user_model.UserOpenID{UID: u.ID, URI: oid} - if err := user_model.AddUserOpenID(ctx, userOID); err != nil { - if user_model.IsErrOpenIDAlreadyUsed(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", oid), tplConnectOID, &form) - return - } - ctx.ServerError("AddUserOpenID", err) - return - } - - ctx.Flash.Success(ctx.Tr("settings.add_openid_success")) - handleSignIn(ctx, u, remember) -} - -func prepareRegisterOpenIDPageData(ctx *context.Context) (oid string) { - oid, _ = ctx.Session.Get("openid_verified_uri").(string) - if oid == "" { - ctx.Redirect(setting.AppSubURL + "/user/login/openid") - return "" - } - ctx.Data["Title"] = "OpenID signup" - ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsOpenIDRegister"] = true - ctx.Data["OpenID"] = oid - prepareCommonAuthPageData(ctx, CommonAuthOptions{ - EnableCaptcha: setting.Service.EnableCaptcha, - }) - return oid -} - -// RegisterOpenID shows a form to create a new user authenticated via an OpenID URI -func RegisterOpenID(ctx *context.Context) { - oid := prepareRegisterOpenIDPageData(ctx) - if oid == "" { - return - } - - userName, _ := ctx.Session.Get("openid_determined_username").(string) - if userName != "" { - ctx.Data["user_name"] = userName - } - email, _ := ctx.Session.Get("openid_determined_email").(string) - if email != "" { - ctx.Data["email"] = email - } - ctx.HTML(http.StatusOK, tplSignUpOID) -} - -// RegisterOpenIDPost handles submission of a form to create a new user authenticated via an OpenID URI -func RegisterOpenIDPost(ctx *context.Context) { - oid := prepareRegisterOpenIDPageData(ctx) - if oid == "" { - return - } - - form := web.GetForm[*forms.SignUpOpenIDForm](ctx) - - if setting.Service.AllowOnlyInternalRegistration { - ctx.HTTPError(http.StatusForbidden) - return - } - - if setting.Service.EnableCaptcha { - if err := ctx.Req.ParseForm(); err != nil { - ctx.ServerError("", err) - return - } - if !context.VerifyCaptcha(ctx, tplSignUpOID, form) { - return - } - } - - length := max(setting.MinPasswordLength, 256) - password := util.CryptoRandomString(int64(length)) - - u := &user_model.User{ - Name: form.UserName, - Email: form.Email, - Passwd: password, - } - if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil) { - // error already handled - return - } - - // add OpenID for the user - userOID := &user_model.UserOpenID{UID: u.ID, URI: oid} - if err := user_model.AddUserOpenID(ctx, userOID); err != nil { - if user_model.IsErrOpenIDAlreadyUsed(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", oid), tplSignUpOID, &form) - return - } - ctx.ServerError("AddUserOpenID", err) - return - } - - if !handleUserCreated(ctx, u, nil) { - // error already handled - return - } - - remember, _ := ctx.Session.Get("openid_signin_remember").(bool) - log.Trace("Session stored openid-remember: %t", remember) - handleSignIn(ctx, u, remember) -} diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 0114dc8ea7a..b620c9f1874 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -31,13 +31,6 @@ func prepareContextForProfileBigAvatar(ctx *context.Context) { if setting.Service.UserLocationMapURL != "" { ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location) } - // Show OpenID URIs - openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID) - if err != nil { - ctx.ServerError("GetUserOpenIDs", err) - return - } - ctx.Data["OpenIDs"] = openIDs if len(ctx.ContextUser.Description) != 0 { content, err := markdown.RenderString(markup.NewRenderContext(ctx).WithMetas(markup.ComposeSimpleDocumentMetas()), ctx.ContextUser.Description) if err != nil { diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go deleted file mode 100644 index 06a620a84fc..00000000000 --- a/routers/web/user/setting/security/openid.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2018 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package security - -import ( - "errors" - "fmt" - "net/http" - "time" - - audit_model "gitea.dev/models/audit" - user_model "gitea.dev/models/user" - "gitea.dev/modules/auth/openid" - "gitea.dev/modules/base" - "gitea.dev/modules/log" - "gitea.dev/modules/setting" - "gitea.dev/modules/util" - "gitea.dev/modules/web" - "gitea.dev/services/audit" - "gitea.dev/services/context" - "gitea.dev/services/forms" -) - -const openIDAssociationCodeMinutes = 10 - -// OpenIDPost response for change user's openid -func OpenIDPost(ctx *context.Context) { - if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) { - ctx.HTTPError(http.StatusNotFound) - return - } - - form := web.GetForm[*forms.AddOpenIDForm](ctx) - ctx.Data["Title"] = ctx.Tr("settings_title") - ctx.Data["PageIsSettingsSecurity"] = true - - if ctx.HasError() { - loadSecurityData(ctx) - - ctx.HTML(http.StatusOK, tplSettingsSecurity) - return - } - - // WARNING: specifying a wrong OpenID here could lock - // a user out of her account, would be better to - // verify/confirm the new OpenID before storing it - - // Also, consider allowing for multiple OpenID URIs - - id, err := openid.Normalize(form.Openid) - if err != nil { - loadSecurityData(ctx) - - ctx.RenderWithErrDeprecated(err.Error(), tplSettingsSecurity, &form) - return - } - form.Openid = id - log.Trace("Normalized id: " + id) - - oids, err := user_model.GetUserOpenIDs(ctx, ctx.Doer.ID) - if err != nil { - ctx.ServerError("GetUserOpenIDs", err) - return - } - ctx.Data["OpenIDs"] = oids - - // Check that the OpenID is not already used - for _, obj := range oids { - if obj.URI == id { - loadSecurityData(ctx) - - ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &form) - return - } - } - - state := base.CreateTimeLimitCode(fmt.Sprintf("openid_association:%d", ctx.Doer.ID), openIDAssociationCodeMinutes, time.Now(), nil) - redirectTo := setting.AppURL + "user/settings/security?state=" + state - url, err := openid.RedirectURL(id, redirectTo, setting.AppURL) - if err != nil { - loadSecurityData(ctx) - - ctx.RenderWithErrDeprecated(err.Error(), tplSettingsSecurity, &form) - return - } - ctx.Redirect(url) -} - -func settingsOpenIDVerify(ctx *context.Context) { - if !base.VerifyTimeLimitCode(time.Now(), fmt.Sprintf("openid_association:%d", ctx.Doer.ID), openIDAssociationCodeMinutes, ctx.FormString("state")) { - ctx.HTTPError(http.StatusForbidden) - return - } - - log.Trace("Incoming call to: " + ctx.Req.URL.String()) - - fullURL := setting.AppURL + ctx.Req.URL.String()[1:] - log.Trace("Full URL: " + fullURL) - - id, err := openid.Verify(fullURL) - if err != nil { - ctx.RenderWithErrDeprecated(err.Error(), tplSettingsSecurity, &forms.AddOpenIDForm{ - Openid: id, - }) - return - } - - log.Trace("Verified ID: " + id) - - oid := &user_model.UserOpenID{UID: ctx.Doer.ID, URI: id} - if err = user_model.AddUserOpenID(ctx, oid); err != nil { - if user_model.IsErrOpenIDAlreadyUsed(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &forms.AddOpenIDForm{Openid: id}) - return - } - ctx.ServerError("AddUserOpenID", err) - return - } - log.Trace("Associated OpenID %s to user %s", id, ctx.Doer.Name) - - audit.Record(ctx, audit_model.UserOpenIDAdd, ctx.Doer, "openid", oid.URI) - - ctx.Flash.Success(ctx.Tr("settings.add_openid_success")) - - ctx.Redirect(setting.AppSubURL + "/user/settings/security") -} - -// DeleteOpenID response for delete user's openid -func DeleteOpenID(ctx *context.Context) { - if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) { - ctx.HTTPError(http.StatusNotFound) - return - } - - oid, err := user_model.GetUserOpenIDByID(ctx, ctx.FormInt64("id"), ctx.Doer.ID) - if err != nil { - if errors.Is(err, util.ErrNotExist) { - ctx.HTTPError(http.StatusNotFound) - } else { - ctx.ServerError("GetUserOpenIDByID", err) - } - return - } - - if err := user_model.DeleteUserOpenID(ctx, oid); err != nil { - if errors.Is(err, util.ErrNotExist) { - ctx.HTTPError(http.StatusNotFound) - } else { - ctx.ServerError("DeleteUserOpenID", err) - } - return - } - - audit.Record(ctx, audit_model.UserOpenIDRemove, ctx.Doer, "openid", oid.URI) - - log.Trace("OpenID address deleted: %s", ctx.Doer.Name) - - ctx.Flash.Success(ctx.Tr("settings.openid_deletion_success")) - ctx.JSONRedirect(setting.AppSubURL + "/user/settings/security") -} - -// ToggleOpenIDVisibility response for toggle visibility of user's openid -func ToggleOpenIDVisibility(ctx *context.Context) { - if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) { - ctx.HTTPError(http.StatusNotFound) - return - } - - if err := user_model.ToggleUserOpenIDVisibility(ctx, ctx.FormInt64("id"), ctx.Doer); err != nil { - if errors.Is(err, util.ErrNotExist) { - ctx.HTTPError(http.StatusNotFound) - } else { - ctx.ServerError("ToggleUserOpenIDVisibility", err) - } - return - } - - ctx.Redirect(setting.AppSubURL + "/user/settings/security") -} diff --git a/routers/web/user/setting/security/openid_test.go b/routers/web/user/setting/security/openid_test.go deleted file mode 100644 index f0c7432decb..00000000000 --- a/routers/web/user/setting/security/openid_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package security - -import ( - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "testing" - "time" - - "gitea.dev/models/unittest" - user_model "gitea.dev/models/user" - "gitea.dev/modules/base" - "gitea.dev/modules/setting" - "gitea.dev/modules/test" - "gitea.dev/modules/web" - "gitea.dev/services/context" - "gitea.dev/services/contexttest" - "gitea.dev/services/forms" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestOpenIDAssociation(t *testing.T) { - unittest.PrepareTestEnv(t) - defer test.MockVariableValue(&setting.AppURL, "https://gitea.example/")() - defer test.MockVariableValue(&setting.AppSubURL, "")() - defer test.MockVariableValue(&setting.Security.AllowedHostList, "127.0.0.1:*")() - - provider := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == http.MethodPost { - assert.Equal(t, "check_authentication", r.FormValue("openid.mode")) - w.Header().Set("Content-Type", "text/plain") - fmt.Fprint(w, "ns:http://specs.openid.net/auth/2.0\nis_valid:true\n") - return - } - w.Header().Set("Content-Type", "text/html") - fmt.Fprintf(w, ``, r.Host) - })) - defer provider.Close() - identity := provider.URL + "/identity" - ctx, resp := contexttest.MockContext(t, "POST /user/settings/security/openid") - contexttest.LoadUser(t, ctx, 2) - web.SetForm(ctx, &forms.AddOpenIDForm{Openid: identity}) - OpenIDPost(ctx) - require.Equal(t, http.StatusSeeOther, resp.Code) - redirect, err := url.Parse(resp.Header().Get("Location")) - require.NoError(t, err) - callback, err := url.Parse(redirect.Query().Get("openid.return_to")) - require.NoError(t, err) - state := callback.Query().Get("state") - require.NotEmpty(t, state) - - params := url.Values{ - "openid.ns": {"http://specs.openid.net/auth/2.0"}, - "openid.mode": {"id_res"}, - "openid.op_endpoint": {provider.URL + "/provider"}, - "openid.claimed_id": {identity}, - "openid.identity": {identity}, - "openid.return_to": {callback.String()}, - "openid.response_nonce": {time.Now().UTC().Format("2006-01-02T15:04:05Z") + "association"}, - "openid.assoc_handle": {"test-association"}, - "openid.signed": {"op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle"}, - "openid.sig": {"test-signature"}, - } - for _, tc := range []struct { - name string - uid int64 - state string - }{ - {"unsolicited", 2, ""}, - {"wrong state", 2, "wrong"}, - {"other user", 1, state}, - {"expired", 2, base.CreateTimeLimitCode("openid_association:2", openIDAssociationCodeMinutes, time.Now().Add(-time.Hour), nil)}, - {"other purpose", 2, base.CreateTimeLimitCode("reset_password:2", openIDAssociationCodeMinutes, time.Now(), nil)}, - } { - t.Run(tc.name, func(t *testing.T) { - params.Set("state", tc.state) - ctx, resp := contexttest.MockContext(t, "GET /user/settings/security?"+params.Encode()) - contexttest.LoadUser(t, ctx, tc.uid) - Security(ctx) - assert.Equal(t, http.StatusForbidden, resp.Code) - unittest.AssertNotExistsBean(t, &user_model.UserOpenID{URI: identity}) - }) - } - - params.Set("state", state) - ctx, resp = contexttest.MockContext(t, "GET /user/settings/security?"+params.Encode()) - contexttest.LoadUser(t, ctx, 2) - Security(ctx) - require.Equal(t, http.StatusSeeOther, resp.Code) - unittest.AssertExistsAndLoadBean(t, &user_model.UserOpenID{UID: 2, URI: identity}) - - ctx, resp = contexttest.MockContext(t, "GET /user/settings/security?"+params.Encode()) - contexttest.LoadUser(t, ctx, 2) - Security(ctx) - assert.Equal(t, http.StatusOK, resp.Code) - assert.Equal(t, "Nonce already used", ctx.Flash.ErrorMsg) -} - -func TestOpenIDReturnsNotFoundForOtherUsersAddress(t *testing.T) { - unittest.PrepareTestEnv(t) - for _, handler := range []func(*context.Context){DeleteOpenID, ToggleOpenIDVisibility} { - ctx, _ := contexttest.MockContext(t, "POST /user/settings/security?id=1") - contexttest.LoadUser(t, ctx, 2) - handler(ctx) - assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus()) - } -} diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index c7132430fd7..8667402fc10 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -36,11 +36,6 @@ func Security(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings.security") ctx.Data["PageIsSettingsSecurity"] = true - if ctx.FormString("openid.return_to") != "" { - settingsOpenIDVerify(ctx) - return - } - loadSecurityData(ctx) ctx.HTML(http.StatusOK, tplSettingsSecurity) @@ -153,11 +148,4 @@ func loadSecurityData(ctx *context.Context) { ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names ctx.Data["OAuth2Providers"] = oauth2Providers - - openid, err := user_model.GetUserOpenIDs(ctx, ctx.Doer.ID) - if err != nil { - ctx.ServerError("GetUserOpenIDs", err) - return - } - ctx.Data["OpenIDs"] = openid } diff --git a/routers/web/web.go b/routers/web/web.go index 1c2ddbb2cda..8d7b5510597 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -358,20 +358,6 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { // middleware: only apply CrossOriginProtection crossOriginProtect := verifyAuthWithOptionsWeb(&common.VerifyOptions{DisableCrossOriginProtection: false}) - openIDSignInEnabled := func(ctx *context.Context) { - if !setting.Service.EnableOpenIDSignIn { - ctx.HTTPError(http.StatusForbidden) - return - } - } - - openIDSignUpEnabled := func(ctx *context.Context) { - if !setting.Service.EnableOpenIDSignUp { - ctx.HTTPError(http.StatusForbidden) - return - } - } - oauth2Enabled := func(ctx *context.Context) { if !setting.OAuth2.Enabled { ctx.HTTPError(http.StatusForbidden) @@ -579,21 +565,6 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/user/login", auth.SignIn) m.Group("/user", func() { m.Post("/login", web.Bind[*forms.SignInForm](), auth.SignInPost) - m.Group("", func() { - m.Combo("/login/openid"). - Get(auth.SignInOpenID). - Post(web.Bind[*forms.SignInOpenIDForm](), auth.SignInOpenIDPost) - }, openIDSignInEnabled) - m.Group("/openid", func() { - m.Combo("/connect"). - Get(auth.ConnectOpenID). - Post(web.Bind[*forms.ConnectOpenIDForm](), auth.ConnectOpenIDPost) - m.Group("/register", func() { - m.Combo(""). - Get(auth.RegisterOpenID, openIDSignUpEnabled). - Post(web.Bind[*forms.SignUpOpenIDForm](), auth.RegisterOpenIDPost) - }, openIDSignUpEnabled) - }, openIDSignInEnabled) m.Get("/sign_up", auth.SignUp) m.Post("/sign_up", web.Bind[*forms.RegisterForm](), auth.SignUpPost) m.Get("/link_account", auth.LinkAccount) @@ -671,11 +642,6 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Post("/rename", security.WebauthnRename) m.Post("/delete", security.WebauthnDelete) }) - m.Group("/openid", func() { - m.Post("", web.Bind[*forms.AddOpenIDForm](), security.OpenIDPost) - m.Post("/delete", security.DeleteOpenID) - m.Post("/toggle_visibility", security.ToggleOpenIDVisibility) - }, openIDSignInEnabled) m.Post("/account_link", security.DeleteAccountLink) }) diff --git a/services/auth/session.go b/services/auth/session.go index 8cb83dfa9d1..6a83d0b320d 100644 --- a/services/auth/session.go +++ b/services/auth/session.go @@ -61,14 +61,9 @@ func (s *Session) Verify(req *http.Request, w http.ResponseWriter, store DataSto } func ClearSessionKeysForSignIn(sess SessionStore) { - _ = sess.Delete("openid_verified_uri") - _ = sess.Delete("openid_signin_remember") - _ = sess.Delete("openid_determined_email") - _ = sess.Delete("openid_determined_username") _ = sess.Delete("twofaUid") _ = sess.Delete("twofaRemember") _ = sess.Delete("webauthnAssertion") _ = sess.Delete("linkAccount") _ = sess.Delete("linkAccountData") - _ = sess.Delete("openidPendingURI") } diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 26ea642d50c..7f3af1ffe05 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -17,7 +17,6 @@ import ( user_model "gitea.dev/models/user" "gitea.dev/modules/log" "gitea.dev/modules/optional" - "gitea.dev/modules/setting" "gitea.dev/modules/templates" "gitea.dev/services/audit" "gitea.dev/services/auth/source/sspi" @@ -87,7 +86,6 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, store.GetData()["Flash"] = map[string]string{ "ErrorMsg": err.Error(), } - store.GetData()["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn store.GetData()["EnableSSPI"] = true // in this case, the Verify function is called in Gitea's web context // FIXME: it doesn't look good to render the page here, why not redirect? diff --git a/services/forms/user_form.go b/services/forms/user_form.go index fda746a8843..b1e9a90bf34 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -206,12 +206,6 @@ type ChangePasswordForm struct { Retype string `form:"retype"` } -// AddOpenIDForm is for changing openid uri -type AddOpenIDForm struct { - middleware.FormDefaultValidator - Openid string `binding:"Required;MaxSize(256)"` -} - // AddKeyForm form for adding SSH/GPG key type AddKeyForm struct { middleware.FormDefaultValidator diff --git a/services/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go deleted file mode 100644 index 052473e53ac..00000000000 --- a/services/forms/user_form_auth_openid.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package forms - -import "gitea.dev/modules/web/middleware" - -// SignInOpenIDForm form for signing in with OpenID -type SignInOpenIDForm struct { - middleware.FormDefaultValidator - Openid string `binding:"Required;MaxSize(256)"` - Remember bool -} - -// SignUpOpenIDForm form for signin up with OpenID -type SignUpOpenIDForm struct { - middleware.FormDefaultValidator - UserName string `binding:"Required;Username;MaxSize(40)"` - Email string `binding:"Required;Email;MaxSize(254)"` -} - -// ConnectOpenIDForm form for connecting an existing account to an OpenID URI -type ConnectOpenIDForm struct { - middleware.FormDefaultValidator - UserName string `binding:"Required;MaxSize(254)"` - Password string `binding:"Required;MaxSize(255)"` -} diff --git a/services/user/delete.go b/services/user/delete.go index 9f3ca48b34c..de58917a622 100644 --- a/services/user/delete.go +++ b/services/user/delete.go @@ -82,7 +82,6 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) &activities_model.Action{UserID: u.ID}, &issues_model.IssueUser{UID: u.ID}, &user_model.EmailAddress{UID: u.ID}, - &user_model.UserOpenID{UID: u.ID}, &issues_model.Reaction{UserID: u.ID}, &organization.TeamUser{UID: u.ID}, &issues_model.Stopwatch{UserID: u.ID}, diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 31667a7ab12..98cb2de6883 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -133,10 +133,6 @@
{{svg (Iif .Service.AllowOnlyExternalRegistration "octicon-check" "octicon-x")}}
{{ctx.Locale.Tr "admin.config.show_registration_button"}}
{{svg (Iif .Service.ShowRegistrationButton "octicon-check" "octicon-x")}}
-
{{ctx.Locale.Tr "admin.config.enable_openid_signup"}}
-
{{svg (Iif .Service.EnableOpenIDSignUp "octicon-check" "octicon-x")}}
-
{{ctx.Locale.Tr "admin.config.enable_openid_signin"}}
-
{{svg (Iif .Service.EnableOpenIDSignIn "octicon-check" "octicon-x")}}
{{ctx.Locale.Tr "admin.config.require_sign_in_view"}}
{{svg (Iif .Service.RequireSignInViewStrict "octicon-check" "octicon-x")}}
{{ctx.Locale.Tr "admin.config.mail_notify"}}
diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index 47d23a5729a..be0d5bdcc8c 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -78,15 +78,6 @@ {{end}} - {{range .OpenIDs}} - {{if .Show}} -
- {{svg "fontawesome-openid"}} - {{.URI}} -
- {{end}} - {{end}} -
{{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (DateUtils.AbsoluteShort .ContextUser.CreatedUnix)}}
{{if and .Orgs .HasOrgsVisible}} diff --git a/templates/user/auth/external_auth_methods.tmpl b/templates/user/auth/external_auth_methods.tmpl index 119be95d8bb..a28f4de6971 100644 --- a/templates/user/auth/external_auth_methods.tmpl +++ b/templates/user/auth/external_auth_methods.tmpl @@ -4,11 +4,6 @@ {{$provider.IconHTML 24}} {{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}} {{end}} - {{if .EnableOpenIDSignIn}} - - {{end}} {{if .EnableSSPI}} -{{template "base/footer" .}} diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl index a03e40c7b1b..945b4a9756d 100644 --- a/templates/user/auth/signup_inner.tmpl +++ b/templates/user/auth/signup_inner.tmpl @@ -49,7 +49,7 @@ {{end}} - {{$showExternalAuthMethods := or .OAuth2Providers .EnableOpenIDSignIn .EnableSSPI}} + {{$showExternalAuthMethods := or .OAuth2Providers .EnableSSPI}} {{if $showExternalAuthMethods}}
{{ctx.Locale.Tr "sign_in_or"}}
{{template "user/auth/external_auth_methods" .}} diff --git a/templates/user/auth/signup_openid_connect.tmpl b/templates/user/auth/signup_openid_connect.tmpl deleted file mode 100644 index 948a47d8f39..00000000000 --- a/templates/user/auth/signup_openid_connect.tmpl +++ /dev/null @@ -1,35 +0,0 @@ -{{template "base/head" .}} - -{{template "base/footer" .}} diff --git a/templates/user/auth/signup_openid_navbar.tmpl b/templates/user/auth/signup_openid_navbar.tmpl deleted file mode 100644 index 89068ddde18..00000000000 --- a/templates/user/auth/signup_openid_navbar.tmpl +++ /dev/null @@ -1,12 +0,0 @@ - -
- - {{ctx.Locale.Tr "auth.openid_connect_title"}} - - {{if and .EnableOpenIDSignUp (not .AllowOnlyInternalRegistration)}} - - {{ctx.Locale.Tr "auth.openid_register_title"}} - - {{end}} -
-
diff --git a/templates/user/auth/signup_openid_register.tmpl b/templates/user/auth/signup_openid_register.tmpl deleted file mode 100644 index a9889cae66c..00000000000 --- a/templates/user/auth/signup_openid_register.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -{{template "base/head" .}} - -{{template "base/footer" .}} diff --git a/templates/user/settings/security/openid.tmpl b/templates/user/settings/security/openid.tmpl deleted file mode 100644 index e594f9c5b01..00000000000 --- a/templates/user/settings/security/openid.tmpl +++ /dev/null @@ -1,61 +0,0 @@ -

- {{ctx.Locale.Tr "settings.manage_openid"}} -

-
-
-
- {{ctx.Locale.Tr "settings.openid_desc"}} -
- {{range .OpenIDs}} -
-
- {{svg "fontawesome-openid" 20}} -
-
-
{{.URI}}
-
-
-
- - {{if .Show}} - - {{else}} - - {{end}} -
- -
-
- {{end}} -
-
-
-
-
- - -
- -
- - -
- {{svg "octicon-trash"}} - {{ctx.Locale.Tr "settings.openid_deletion"}} -
-
-

{{ctx.Locale.Tr "settings.openid_deletion_desc"}}

-
- {{template "base/modal_actions_confirm" .}} -
-
diff --git a/templates/user/settings/security/security.tmpl b/templates/user/settings/security/security.tmpl index 90e44ba9416..9eb1a23b216 100644 --- a/templates/user/settings/security/security.tmpl +++ b/templates/user/settings/security/security.tmpl @@ -7,9 +7,6 @@ {{end}} {{if not ($.UserDisabledFeatures.Contains "manage_credentials")}} {{template "user/settings/security/accountlinks" .}} - {{if .EnableOpenIDSignIn}} - {{template "user/settings/security/openid" .}} - {{end}} {{end}} {{end}} diff --git a/web_src/svg/fontawesome-openid.svg b/web_src/svg/fontawesome-openid.svg deleted file mode 100644 index ea145d5506f..00000000000 --- a/web_src/svg/fontawesome-openid.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file