Skip to content

Commit 4818a72

Browse files
committed
Merge remote-tracking branch 'origin/main' into oidc-claims
2 parents a730e6b + 123f0ae commit 4818a72

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+341
-227
lines changed

cmd/admin_auth_ldap.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ var (
9393
Name: "skip-local-2fa",
9494
Usage: "Set to true to skip local 2fa for users authenticated by this source",
9595
},
96+
cli.StringFlag{
97+
Name: "avatar-attribute",
98+
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
99+
},
96100
}
97101

98102
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
@@ -234,6 +238,9 @@ func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
234238
if c.IsSet("public-ssh-key-attribute") {
235239
config.AttributeSSHPublicKey = c.String("public-ssh-key-attribute")
236240
}
241+
if c.IsSet("avatar-attribute") {
242+
config.AttributeAvatar = c.String("avatar-attribute")
243+
}
237244
if c.IsSet("page-size") {
238245
config.SearchPageSize = uint32(c.Uint("page-size"))
239246
}

cmd/admin_auth_ldap_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestAddLdapBindDn(t *testing.T) {
4545
"--surname-attribute", "sn-bind full",
4646
"--email-attribute", "mail-bind full",
4747
"--public-ssh-key-attribute", "publickey-bind full",
48+
"--avatar-attribute", "avatar-bind full",
4849
"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
4950
"--bind-password", "secret-bind-full",
5051
"--attributes-in-bind",
@@ -71,6 +72,7 @@ func TestAddLdapBindDn(t *testing.T) {
7172
AttributeMail: "mail-bind full",
7273
AttributesInBind: true,
7374
AttributeSSHPublicKey: "publickey-bind full",
75+
AttributeAvatar: "avatar-bind full",
7476
SearchPageSize: 99,
7577
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
7678
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
@@ -269,6 +271,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
269271
"--surname-attribute", "sn-simple full",
270272
"--email-attribute", "mail-simple full",
271273
"--public-ssh-key-attribute", "publickey-simple full",
274+
"--avatar-attribute", "avatar-simple full",
272275
"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
273276
},
274277
loginSource: &login.Source{
@@ -288,6 +291,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
288291
AttributeSurname: "sn-simple full",
289292
AttributeMail: "mail-simple full",
290293
AttributeSSHPublicKey: "publickey-simple full",
294+
AttributeAvatar: "avatar-simple full",
291295
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
292296
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
293297
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
@@ -501,6 +505,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
501505
"--surname-attribute", "sn-bind full",
502506
"--email-attribute", "mail-bind full",
503507
"--public-ssh-key-attribute", "publickey-bind full",
508+
"--avatar-attribute", "avatar-bind full",
504509
"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
505510
"--bind-password", "secret-bind-full",
506511
"--synchronize-users",
@@ -534,6 +539,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
534539
AttributeMail: "mail-bind full",
535540
AttributesInBind: false,
536541
AttributeSSHPublicKey: "publickey-bind full",
542+
AttributeAvatar: "avatar-bind full",
537543
SearchPageSize: 99,
538544
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
539545
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
@@ -932,6 +938,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
932938
"--surname-attribute", "sn-simple full",
933939
"--email-attribute", "mail-simple full",
934940
"--public-ssh-key-attribute", "publickey-simple full",
941+
"--avatar-attribute", "avatar-simple full",
935942
"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
936943
},
937944
id: 7,
@@ -952,6 +959,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
952959
AttributeSurname: "sn-simple full",
953960
AttributeMail: "mail-simple full",
954961
AttributeSSHPublicKey: "publickey-simple full",
962+
AttributeAvatar: "avatar-simple full",
955963
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
956964
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
957965
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",

docs/content/doc/usage/command-line.en-us.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Admin operations:
166166
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
167167
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
168168
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
169+
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
169170
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
170171
- `--bind-password value`: The password for the Bind DN, if any.
171172
- `--attributes-in-bind`: Fetch attributes in bind DN context.
@@ -191,6 +192,7 @@ Admin operations:
191192
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
192193
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
193194
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
195+
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
194196
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
195197
- `--bind-password value`: The password for the Bind DN, if any.
196198
- `--attributes-in-bind`: Fetch attributes in bind DN context.
@@ -216,6 +218,7 @@ Admin operations:
216218
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
217219
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
218220
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
221+
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
219222
- `--user-dn value`: The user’s DN. Required.
220223
- Examples:
221224
- `gitea admin auth add-ldap-simple --name ldap --security-protocol unencrypted --host mydomain.org --port 389 --user-dn "cn=%s,ou=Users,dc=mydomain,dc=org" --user-filter "(&(objectClass=posixAccount)(cn=%s))" --email-attribute mail`
@@ -237,6 +240,7 @@ Admin operations:
237240
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
238241
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
239242
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
243+
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
240244
- `--user-dn value`: The user’s DN.
241245
- Examples:
242246
- `gitea admin auth update-ldap-simple --id 1 --name "my ldap auth source"`

models/error.go

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,25 +1876,6 @@ func (err ErrTeamNotExist) Error() string {
18761876
return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
18771877
}
18781878

1879-
//
1880-
// Two-factor authentication
1881-
//
1882-
1883-
// ErrTwoFactorNotEnrolled indicates that a user is not enrolled in two-factor authentication.
1884-
type ErrTwoFactorNotEnrolled struct {
1885-
UID int64
1886-
}
1887-
1888-
// IsErrTwoFactorNotEnrolled checks if an error is a ErrTwoFactorNotEnrolled.
1889-
func IsErrTwoFactorNotEnrolled(err error) bool {
1890-
_, ok := err.(ErrTwoFactorNotEnrolled)
1891-
return ok
1892-
}
1893-
1894-
func (err ErrTwoFactorNotEnrolled) Error() string {
1895-
return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID)
1896-
}
1897-
18981879
// ____ ___ .__ .___
18991880
// | | \______ | | _________ __| _/
19001881
// | | /\____ \| | / _ \__ \ / __ |
@@ -1959,28 +1940,6 @@ func (err ErrExternalLoginUserNotExist) Error() string {
19591940
return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID)
19601941
}
19611942

1962-
// ____ ________________________________ .__ __ __ .__
1963-
// | | \_____ \_ _____/\______ \ ____ ____ |__| _______/ |_____________ _/ |_|__| ____ ____
1964-
// | | // ____/| __) | _// __ \ / ___\| |/ ___/\ __\_ __ \__ \\ __\ |/ _ \ / \
1965-
// | | // \| \ | | \ ___// /_/ > |\___ \ | | | | \// __ \| | | ( <_> ) | \
1966-
// |______/ \_______ \___ / |____|_ /\___ >___ /|__/____ > |__| |__| (____ /__| |__|\____/|___| /
1967-
// \/ \/ \/ \/_____/ \/ \/ \/
1968-
1969-
// ErrU2FRegistrationNotExist represents a "ErrU2FRegistrationNotExist" kind of error.
1970-
type ErrU2FRegistrationNotExist struct {
1971-
ID int64
1972-
}
1973-
1974-
func (err ErrU2FRegistrationNotExist) Error() string {
1975-
return fmt.Sprintf("U2F registration does not exist [id: %d]", err.ID)
1976-
}
1977-
1978-
// IsErrU2FRegistrationNotExist checks if an error is a ErrU2FRegistrationNotExist.
1979-
func IsErrU2FRegistrationNotExist(err error) bool {
1980-
_, ok := err.(ErrU2FRegistrationNotExist)
1981-
return ok
1982-
}
1983-
19841943
// .___ ________ .___ .__
19851944
// | | ______ ________ __ ____ \______ \ ____ ______ ____ ____ __| _/____ ____ ____ |__| ____ ______
19861945
// | |/ ___// ___/ | \_/ __ \ | | \_/ __ \\____ \_/ __ \ / \ / __ |/ __ \ / \_/ ___\| |/ __ \ / ___/

models/login/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ func TestMain(m *testing.M) {
1717
"oauth2_application.yml",
1818
"oauth2_authorization_code.yml",
1919
"oauth2_grant.yml",
20+
"u2f_registration.yml",
2021
)
2122
}

models/twofactor.go renamed to models/login/twofactor.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
88
"crypto/md5"
@@ -21,6 +21,25 @@ import (
2121
"golang.org/x/crypto/pbkdf2"
2222
)
2323

24+
//
25+
// Two-factor authentication
26+
//
27+
28+
// ErrTwoFactorNotEnrolled indicates that a user is not enrolled in two-factor authentication.
29+
type ErrTwoFactorNotEnrolled struct {
30+
UID int64
31+
}
32+
33+
// IsErrTwoFactorNotEnrolled checks if an error is a ErrTwoFactorNotEnrolled.
34+
func IsErrTwoFactorNotEnrolled(err error) bool {
35+
_, ok := err.(ErrTwoFactorNotEnrolled)
36+
return ok
37+
}
38+
39+
func (err ErrTwoFactorNotEnrolled) Error() string {
40+
return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID)
41+
}
42+
2443
// TwoFactor represents a two-factor authentication token.
2544
type TwoFactor struct {
2645
ID int64 `xorm:"pk autoincr"`
@@ -44,11 +63,12 @@ func (t *TwoFactor) GenerateScratchToken() (string, error) {
4463
return "", err
4564
}
4665
t.ScratchSalt, _ = util.RandomString(10)
47-
t.ScratchHash = hashToken(token, t.ScratchSalt)
66+
t.ScratchHash = HashToken(token, t.ScratchSalt)
4867
return token, nil
4968
}
5069

51-
func hashToken(token, salt string) string {
70+
// HashToken return the hashable salt
71+
func HashToken(token, salt string) string {
5272
tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New)
5373
return fmt.Sprintf("%x", tempHash)
5474
}
@@ -58,7 +78,7 @@ func (t *TwoFactor) VerifyScratchToken(token string) bool {
5878
if len(token) == 0 {
5979
return false
6080
}
61-
tempHash := hashToken(token, t.ScratchSalt)
81+
tempHash := HashToken(token, t.ScratchSalt)
6282
return subtle.ConstantTimeCompare([]byte(t.ScratchHash), []byte(tempHash)) == 1
6383
}
6484

models/u2f.go renamed to models/login/u2f.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,40 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
8+
"fmt"
9+
810
"code.gitea.io/gitea/models/db"
911
"code.gitea.io/gitea/modules/log"
1012
"code.gitea.io/gitea/modules/timeutil"
1113

1214
"github.com/tstranex/u2f"
1315
)
1416

17+
// ____ ________________________________ .__ __ __ .__
18+
// | | \_____ \_ _____/\______ \ ____ ____ |__| _______/ |_____________ _/ |_|__| ____ ____
19+
// | | // ____/| __) | _// __ \ / ___\| |/ ___/\ __\_ __ \__ \\ __\ |/ _ \ / \
20+
// | | // \| \ | | \ ___// /_/ > |\___ \ | | | | \// __ \| | | ( <_> ) | \
21+
// |______/ \_______ \___ / |____|_ /\___ >___ /|__/____ > |__| |__| (____ /__| |__|\____/|___| /
22+
// \/ \/ \/ \/_____/ \/ \/ \/
23+
24+
// ErrU2FRegistrationNotExist represents a "ErrU2FRegistrationNotExist" kind of error.
25+
type ErrU2FRegistrationNotExist struct {
26+
ID int64
27+
}
28+
29+
func (err ErrU2FRegistrationNotExist) Error() string {
30+
return fmt.Sprintf("U2F registration does not exist [id: %d]", err.ID)
31+
}
32+
33+
// IsErrU2FRegistrationNotExist checks if an error is a ErrU2FRegistrationNotExist.
34+
func IsErrU2FRegistrationNotExist(err error) bool {
35+
_, ok := err.(ErrU2FRegistrationNotExist)
36+
return ok
37+
}
38+
1539
// U2FRegistration represents the registration data and counter of a security key
1640
type U2FRegistration struct {
1741
ID int64 `xorm:"pk autoincr"`
@@ -91,13 +115,13 @@ func GetU2FRegistrationsByUID(uid int64) (U2FRegistrationList, error) {
91115
return getU2FRegistrationsByUID(db.GetEngine(db.DefaultContext), uid)
92116
}
93117

94-
func createRegistration(e db.Engine, user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) {
118+
func createRegistration(e db.Engine, userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
95119
raw, err := reg.MarshalBinary()
96120
if err != nil {
97121
return nil, err
98122
}
99123
r := &U2FRegistration{
100-
UserID: user.ID,
124+
UserID: userID,
101125
Name: name,
102126
Counter: 0,
103127
Raw: raw,
@@ -110,8 +134,8 @@ func createRegistration(e db.Engine, user *User, name string, reg *u2f.Registrat
110134
}
111135

112136
// CreateRegistration will create a new U2FRegistration from the given Registration
113-
func CreateRegistration(user *User, name string, reg *u2f.Registration) (*U2FRegistration, error) {
114-
return createRegistration(db.GetEngine(db.DefaultContext), user, name, reg)
137+
func CreateRegistration(userID int64, name string, reg *u2f.Registration) (*U2FRegistration, error) {
138+
return createRegistration(db.GetEngine(db.DefaultContext), userID, name, reg)
115139
}
116140

117141
// DeleteRegistration will delete U2FRegistration

models/u2f_test.go renamed to models/login/u2f_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package models
5+
package login
66

77
import (
88
"testing"
99

1010
"code.gitea.io/gitea/models/db"
11+
1112
"github.com/stretchr/testify/assert"
1213
"github.com/tstranex/u2f"
1314
)
@@ -55,14 +56,13 @@ func TestU2FRegistration_UpdateLargeCounter(t *testing.T) {
5556

5657
func TestCreateRegistration(t *testing.T) {
5758
assert.NoError(t, db.PrepareTestDatabase())
58-
user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
5959

60-
res, err := CreateRegistration(user, "U2F Created Key", &u2f.Registration{Raw: []byte("Test")})
60+
res, err := CreateRegistration(1, "U2F Created Key", &u2f.Registration{Raw: []byte("Test")})
6161
assert.NoError(t, err)
6262
assert.Equal(t, "U2F Created Key", res.Name)
6363
assert.Equal(t, []byte("Test"), res.Raw)
6464

65-
db.AssertExistsIf(t, true, &U2FRegistration{Name: "U2F Created Key", UserID: user.ID})
65+
db.AssertExistsIf(t, true, &U2FRegistration{Name: "U2F Created Key", UserID: 1})
6666
}
6767

6868
func TestDeleteRegistration(t *testing.T) {

models/pull_sign.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package models
66

77
import (
88
"code.gitea.io/gitea/models/db"
9+
"code.gitea.io/gitea/models/login"
910
"code.gitea.io/gitea/modules/git"
1011
"code.gitea.io/gitea/modules/log"
1112
"code.gitea.io/gitea/modules/setting"
@@ -44,8 +45,8 @@ Loop:
4445
return false, "", nil, &ErrWontSign{pubkey}
4546
}
4647
case twofa:
47-
twofaModel, err := GetTwoFactorByUID(u.ID)
48-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
48+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
49+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
4950
return false, "", nil, err
5051
}
5152
if twofaModel == nil {

models/repo_sign.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99

1010
"code.gitea.io/gitea/models/db"
11+
"code.gitea.io/gitea/models/login"
1112
"code.gitea.io/gitea/modules/git"
1213
"code.gitea.io/gitea/modules/log"
1314
"code.gitea.io/gitea/modules/process"
@@ -129,8 +130,8 @@ Loop:
129130
return false, "", nil, &ErrWontSign{pubkey}
130131
}
131132
case twofa:
132-
twofaModel, err := GetTwoFactorByUID(u.ID)
133-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
133+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
134+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
134135
return false, "", nil, err
135136
}
136137
if twofaModel == nil {
@@ -165,8 +166,8 @@ Loop:
165166
return false, "", nil, &ErrWontSign{pubkey}
166167
}
167168
case twofa:
168-
twofaModel, err := GetTwoFactorByUID(u.ID)
169-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
169+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
170+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
170171
return false, "", nil, err
171172
}
172173
if twofaModel == nil {
@@ -218,8 +219,8 @@ Loop:
218219
return false, "", nil, &ErrWontSign{pubkey}
219220
}
220221
case twofa:
221-
twofaModel, err := GetTwoFactorByUID(u.ID)
222-
if err != nil && !IsErrTwoFactorNotEnrolled(err) {
222+
twofaModel, err := login.GetTwoFactorByUID(u.ID)
223+
if err != nil && !login.IsErrTwoFactorNotEnrolled(err) {
223224
return false, "", nil, err
224225
}
225226
if twofaModel == nil {

0 commit comments

Comments
 (0)