This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/log"
|
||||
)
|
||||
|
||||
func UnmarshalGroupTeamMapping(raw string) (map[string]map[string][]string, error) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
type BasicAuth struct {
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
package openid
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitea.dev/modules/hostmatcher"
|
||||
"gitea.dev/modules/proxy"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
"github.com/yohcop/openid-go"
|
||||
)
|
||||
|
||||
@@ -19,11 +25,23 @@ import (
|
||||
var (
|
||||
nonceStore = openid.NewSimpleNonceStore()
|
||||
discoveryCache = newTimedDiscoveryCache(24 * time.Hour)
|
||||
|
||||
// openIDInstance does discovery/verification via an SSRF-protected client, so a user-supplied
|
||||
// OpenID identifier can't reach internal/loopback/reserved addresses. It honors the operator's
|
||||
// [security] ALLOWED_HOST_LIST (empty defaults to "external"), matching the avatar/webhook/migration
|
||||
// clients, and validates the proxy path too. Lazy: reads proxy/settings once.
|
||||
openIDInstance = sync.OnceValue(func() *openid.OpenID {
|
||||
allowList := hostmatcher.ParseHostMatchList("security.ALLOWED_HOST_LIST", setting.Security.AllowedHostList)
|
||||
return openid.NewOpenID(&http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: hostmatcher.NewHTTPTransport("openid", allowList, nil, proxy.Proxy(), setting.Proxy.ProxyURLFixed, nil),
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
// Verify handles response from OpenID provider
|
||||
func Verify(fullURL string) (id string, err error) {
|
||||
return openid.Verify(fullURL, discoveryCache, nonceStore)
|
||||
return openIDInstance().Verify(fullURL, discoveryCache, nonceStore)
|
||||
}
|
||||
|
||||
// Normalize normalizes an OpenID URI
|
||||
@@ -33,5 +51,5 @@ func Normalize(url string) (id string, err error) {
|
||||
|
||||
// RedirectURL redirects browser
|
||||
func RedirectURL(id, callbackURL, realm string) (string, error) {
|
||||
return openid.RedirectURL(id, callbackURL, realm)
|
||||
return openIDInstance().RedirectURL(id, callbackURL, realm)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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")
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
//go:build pam
|
||||
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build pam
|
||||
|
||||
package pam
|
||||
|
||||
import (
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/log"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
@@ -6,8 +6,8 @@ package hash
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
func parseIntParam(value, param, algorithmName, config string, previousErr error) (int, error) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/log"
|
||||
)
|
||||
|
||||
// This package takes care of hashing passwords, verifying passwords, defining
|
||||
|
||||
@@ -74,6 +74,7 @@ func TestHashing(t *testing.T) {
|
||||
runTests := func(password, salt string, shouldPass bool) {
|
||||
for _, algorithmName := range hashAlgorithmsToTest {
|
||||
t.Run(algorithmName, func(t *testing.T) {
|
||||
t.Parallel() // CPU-bound; these subtests only read the shared hasher registry
|
||||
output, err := Parse(algorithmName).Hash(password, salt)
|
||||
if shouldPass {
|
||||
assert.NoError(t, err)
|
||||
@@ -182,6 +183,7 @@ func TestVectors(t *testing.T) {
|
||||
for i, vector := range vectors {
|
||||
for _, algorithm := range vector.algorithms {
|
||||
t.Run(strconv.Itoa(i)+": "+algorithm, func(t *testing.T) {
|
||||
t.Parallel() // CPU-bound; these subtests only read the shared hasher registry
|
||||
pa := Parse(algorithm)
|
||||
assert.Equal(t, !vector.shouldfail, pa.VerifyPassword(vector.password, vector.output, vector.salt))
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/log"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/log"
|
||||
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/translation"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/auth/password/pwn"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"gitea.dev/modules/auth/password/pwn"
|
||||
"gitea.dev/modules/setting"
|
||||
)
|
||||
|
||||
var ErrIsPwned = errors.New("password has been pwned")
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"gitea.dev/modules/setting"
|
||||
)
|
||||
|
||||
const passwordURL = "https://api.pwnedpasswords.com/range/"
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/models/auth"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/util"
|
||||
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
@@ -28,13 +28,10 @@ func Init() {
|
||||
|
||||
WebAuthn = &webauthn.WebAuthn{
|
||||
Config: &webauthn.Config{
|
||||
RPDisplayName: setting.AppName,
|
||||
RPID: setting.Domain,
|
||||
RPOrigins: []string{appURL},
|
||||
AuthenticatorSelection: protocol.AuthenticatorSelection{
|
||||
UserVerification: protocol.VerificationDiscouraged,
|
||||
},
|
||||
AttestationPreference: protocol.PreferDirectAttestation,
|
||||
RPDisplayName: setting.AppName,
|
||||
RPID: setting.Domain,
|
||||
RPOrigins: []string{appURL},
|
||||
AttestationPreference: protocol.PreferNoAttestation, // Gitea never verifies attestation
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package webauthn
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user