Skip to content

Commit

Permalink
Merge remote-tracking branch 'go-gitea/main' into avatar-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
wxiaoguang committed Sep 27, 2021
2 parents 7c65d1e + 123f0ae commit 3852ca4
Show file tree
Hide file tree
Showing 25 changed files with 157 additions and 29 deletions.
7 changes: 7 additions & 0 deletions cmd/admin_auth_ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ var (
Name: "skip-local-2fa",
Usage: "Set to true to skip local 2fa for users authenticated by this source",
},
cli.StringFlag{
Name: "avatar-attribute",
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
},
}

ldapBindDnCLIFlags = append(commonLdapCLIFlags,
Expand Down Expand Up @@ -234,6 +238,9 @@ func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
if c.IsSet("public-ssh-key-attribute") {
config.AttributeSSHPublicKey = c.String("public-ssh-key-attribute")
}
if c.IsSet("avatar-attribute") {
config.AttributeAvatar = c.String("avatar-attribute")
}
if c.IsSet("page-size") {
config.SearchPageSize = uint32(c.Uint("page-size"))
}
Expand Down
8 changes: 8 additions & 0 deletions cmd/admin_auth_ldap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestAddLdapBindDn(t *testing.T) {
"--surname-attribute", "sn-bind full",
"--email-attribute", "mail-bind full",
"--public-ssh-key-attribute", "publickey-bind full",
"--avatar-attribute", "avatar-bind full",
"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
"--bind-password", "secret-bind-full",
"--attributes-in-bind",
Expand All @@ -71,6 +72,7 @@ func TestAddLdapBindDn(t *testing.T) {
AttributeMail: "mail-bind full",
AttributesInBind: true,
AttributeSSHPublicKey: "publickey-bind full",
AttributeAvatar: "avatar-bind full",
SearchPageSize: 99,
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
Expand Down Expand Up @@ -269,6 +271,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
"--surname-attribute", "sn-simple full",
"--email-attribute", "mail-simple full",
"--public-ssh-key-attribute", "publickey-simple full",
"--avatar-attribute", "avatar-simple full",
"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
},
loginSource: &login.Source{
Expand All @@ -288,6 +291,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
AttributeSurname: "sn-simple full",
AttributeMail: "mail-simple full",
AttributeSSHPublicKey: "publickey-simple full",
AttributeAvatar: "avatar-simple full",
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
Expand Down Expand Up @@ -501,6 +505,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
"--surname-attribute", "sn-bind full",
"--email-attribute", "mail-bind full",
"--public-ssh-key-attribute", "publickey-bind full",
"--avatar-attribute", "avatar-bind full",
"--bind-dn", "cn=readonly,dc=full-domain-bind,dc=org",
"--bind-password", "secret-bind-full",
"--synchronize-users",
Expand Down Expand Up @@ -534,6 +539,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
AttributeMail: "mail-bind full",
AttributesInBind: false,
AttributeSSHPublicKey: "publickey-bind full",
AttributeAvatar: "avatar-bind full",
SearchPageSize: 99,
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
Expand Down Expand Up @@ -932,6 +938,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
"--surname-attribute", "sn-simple full",
"--email-attribute", "mail-simple full",
"--public-ssh-key-attribute", "publickey-simple full",
"--avatar-attribute", "avatar-simple full",
"--user-dn", "cn=%s,ou=Users,dc=full-domain-simple,dc=org",
},
id: 7,
Expand All @@ -952,6 +959,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
AttributeSurname: "sn-simple full",
AttributeMail: "mail-simple full",
AttributeSSHPublicKey: "publickey-simple full",
AttributeAvatar: "avatar-simple full",
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
Expand Down
4 changes: 4 additions & 0 deletions docs/content/doc/usage/command-line.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ Admin operations:
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
- `--bind-password value`: The password for the Bind DN, if any.
- `--attributes-in-bind`: Fetch attributes in bind DN context.
Expand All @@ -177,6 +178,7 @@ Admin operations:
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
- `--bind-dn value`: The DN to bind to the LDAP server with when searching for the user.
- `--bind-password value`: The password for the Bind DN, if any.
- `--attributes-in-bind`: Fetch attributes in bind DN context.
Expand All @@ -202,6 +204,7 @@ Admin operations:
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address. Required.
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
- `--user-dn value`: The user’s DN. Required.
- Examples:
- `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`
Expand All @@ -223,6 +226,7 @@ Admin operations:
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
- `--email-attribute value`: The attribute of the user’s LDAP record containing the user’s email address.
- `--public-ssh-key-attribute value`: The attribute of the user’s LDAP record containing the user’s public ssh key.
- `--avatar-attribute value`: The attribute of the user’s LDAP record containing the user’s avatar.
- `--user-dn value`: The user’s DN.
- Examples:
- `gitea admin auth update-ldap-simple --id 1 --name "my ldap auth source"`
Expand Down
9 changes: 9 additions & 0 deletions models/user_avatar.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ func (u *User) UploadAvatar(data []byte) error {
return sess.Commit()
}

// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
func (u *User) IsUploadAvatarChanged(data []byte) bool {
if !u.UseCustomAvatar || len(u.Avatar) == 0 {
return true
}
avatarID := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data)))))
return u.Avatar != avatarID
}

// DeleteAvatar deletes the user's custom avatar.
func (u *User) DeleteAvatar() error {
aPath := u.CustomAvatarRelativePath()
Expand Down
24 changes: 17 additions & 7 deletions modules/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,24 @@ func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.
}
defer os.RemoveAll(tmp)

tmpFile := filepath.Join(tmp, "bundle")
args := []string{
"bundle",
"create",
tmpFile,
commit,
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, err = NewCommandContext(ctx, "init", "--bare").RunInDirWithEnv(tmp, env)
if err != nil {
return err
}

_, err = NewCommandContext(ctx, "reset", "--soft", commit).RunInDirWithEnv(tmp, env)
if err != nil {
return err
}
_, err = NewCommandContext(ctx, args...).RunInDir(repo.Path)

_, err = NewCommandContext(ctx, "branch", "-m", "bundle").RunInDirWithEnv(tmp, env)
if err != nil {
return err
}

tmpFile := filepath.Join(tmp, "bundle")
_, err = NewCommandContext(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunInDirWithEnv(tmp, env)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,7 @@ auths.attribute_name = First Name Attribute
auths.attribute_surname = Surname Attribute
auths.attribute_mail = Email Attribute
auths.attribute_ssh_public_key = Public SSH Key Attribute
auths.attribute_avatar = Avatar Attribute
auths.attributes_in_bind = Fetch Attributes in Bind DN Context
auths.allow_deactivate_all = Allow an empty search result to deactivate all users
auths.use_paged_search = Use Paged Search
Expand Down
6 changes: 3 additions & 3 deletions options/locale/locale_ru-RU.ini
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ public_profile=Открытый профиль
biography_placeholder=Расскажите немного о себе
profile_desc=Ваш адрес электронной почты будет использован для уведомлений и других операций.
password_username_disabled=Нелокальным пользователям запрещено изменение их имени пользователя. Для получения более подробной информации обратитесь к администратору сайта.
full_name=ФИО
full_name=Имя и фамилия
website=Веб-сайт
location=Местоположение
update_theme=Обновить тему
Expand Down Expand Up @@ -1202,8 +1202,8 @@ pulls.merged_by_fake=слито %[1]s пользователем %[2]s
issues.closed_by=закрыт %[1]s пользователем <a href="%[2]s">%[3]s</a>
issues.opened_by_fake=открыт %[1]s пользователем %[2]s
issues.closed_by_fake=закрыт %[1]s пользователем %[2]s
issues.previous=Предыдущая страница
issues.next=Следующая страница
issues.previous=Предыдущая
issues.next=Следующая
issues.open_title=Открыто
issues.closed_title=Закрыто
issues.num_comments=комментариев: %d
Expand Down
7 changes: 5 additions & 2 deletions routers/web/admin/auths.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func parseLDAPConfig(form forms.AuthenticationForm) *ldap.Source {
AttributeMail: form.AttributeMail,
AttributesInBind: form.AttributesInBind,
AttributeSSHPublicKey: form.AttributeSSHPublicKey,
AttributeAvatar: form.AttributeAvatar,
SearchPageSize: pageSize,
Filter: form.Filter,
GroupsEnabled: form.GroupsEnabled,
Expand All @@ -161,6 +162,7 @@ func parseSMTPConfig(form forms.AuthenticationForm) *smtp.Source {
SkipVerify: form.SkipVerify,
HeloHostname: form.HeloHostname,
DisableHelo: form.DisableHelo,
SkipLocalTwoFA: form.SkipLocalTwoFA,
}
}

Expand Down Expand Up @@ -244,8 +246,9 @@ func NewAuthSourcePost(ctx *context.Context) {
hasTLS = true
case login.PAM:
config = &pamService.Source{
ServiceName: form.PAMServiceName,
EmailDomain: form.PAMEmailDomain,
ServiceName: form.PAMServiceName,
EmailDomain: form.PAMEmailDomain,
SkipLocalTwoFA: form.SkipLocalTwoFA,
}
case login.OAuth2:
config = parseOAuth2Config(form)
Expand Down
2 changes: 1 addition & 1 deletion routers/web/user/setting/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func DeleteKey(ctx *context.Context) {
return
}
if external {
ctx.Flash.Error(ctx.Tr("setting.ssh_externally_managed"))
ctx.Flash.Error(ctx.Tr("settings.ssh_externally_managed"))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
return
}
Expand Down
8 changes: 4 additions & 4 deletions routers/web/user/setting/security_twofa.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func RegenerateScratchTwoFactor(ctx *context.Context) {
t, err := login.GetTwoFactorByUID(ctx.User.ID)
if err != nil {
if login.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("setting.twofa_not_enrolled"))
ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
}
ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err)
Expand Down Expand Up @@ -62,7 +62,7 @@ func DisableTwoFactor(ctx *context.Context) {
t, err := login.GetTwoFactorByUID(ctx.User.ID)
if err != nil {
if login.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("setting.twofa_not_enrolled"))
ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
}
ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err)
Expand Down Expand Up @@ -150,7 +150,7 @@ func EnrollTwoFactor(ctx *context.Context) {
if t != nil {
// already enrolled - we should redirect back!
log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.User)
ctx.Flash.Error(ctx.Tr("setting.twofa_is_enrolled"))
ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return
}
Expand All @@ -175,7 +175,7 @@ func EnrollTwoFactorPost(ctx *context.Context) {
t, err := login.GetTwoFactorByUID(ctx.User.ID)
if t != nil {
// already enrolled
ctx.Flash.Error(ctx.Tr("setting.twofa_is_enrolled"))
ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return
}
Expand Down
6 changes: 4 additions & 2 deletions services/archiver/archiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,11 @@ func doArchive(r *ArchiveRequest) (*models.RepoArchiver, error) {
if err == nil {
if archiver.Status == models.RepoArchiverGenerating {
archiver.Status = models.RepoArchiverReady
return archiver, models.UpdateRepoArchiverStatus(ctx, archiver)
if err = models.UpdateRepoArchiverStatus(ctx, archiver); err != nil {
return nil, err
}
}
return archiver, nil
return archiver, committer.Commit()
}

if !errors.Is(err, os.ErrNotExist) {
Expand Down
3 changes: 2 additions & 1 deletion services/auth/source/ldap/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Source struct {
AttributeMail string // E-mail attribute
AttributesInBind bool // fetch attributes in bind context (not user)
AttributeSSHPublicKey string // LDAP SSH Public Key attribute
AttributeAvatar string
SearchPageSize uint32 // Search with paging page size
Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin
Expand All @@ -53,7 +54,7 @@ type Source struct {
GroupFilter string // Group Name Filter
GroupMemberUID string // Group Attribute containing array of UserUID
UserUID string // User Attribute listed in Group
SkipLocalTwoFA bool // Skip Local 2fa for users authenticated with this source
SkipLocalTwoFA bool `json:",omitempty"` // Skip Local 2fa for users authenticated with this source

// reference to the loginSource
loginSource *login.Source
Expand Down
4 changes: 4 additions & 0 deletions services/auth/source/ldap/source_authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func (source *Source) Authenticate(user *models.User, userName, password string)
err = models.RewriteAllPublicKeys()
}

if err == nil && len(source.AttributeAvatar) > 0 {
_ = user.UploadAvatar(sr.Avatar)
}

return user, err
}

Expand Down
27 changes: 22 additions & 5 deletions services/auth/source/ldap/source_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type SearchResult struct {
IsAdmin bool // if user is administrator
IsRestricted bool // if user is restricted
LowerName string // Lowername
Avatar []byte
}

func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
Expand Down Expand Up @@ -266,7 +267,8 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
return nil
}

var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
isAttributeSSHPublicKeySet := len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
isAtributeAvatarSet := len(strings.TrimSpace(ls.AttributeAvatar)) > 0

attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
if len(strings.TrimSpace(ls.UserUID)) > 0 {
Expand All @@ -275,8 +277,11 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
if isAttributeSSHPublicKeySet {
attribs = append(attribs, ls.AttributeSSHPublicKey)
}
if isAtributeAvatarSet {
attribs = append(attribs, ls.AttributeAvatar)
}

log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, ls.UserUID, userFilter, userDN)
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, ls.AttributeAvatar, ls.UserUID, userFilter, userDN)
search := ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
attribs, nil)
Expand All @@ -296,6 +301,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
}

var sshPublicKey []string
var Avatar []byte

username := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
Expand Down Expand Up @@ -363,6 +369,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
}
}

if isAtributeAvatarSet {
Avatar = sr.Entries[0].GetRawAttributeValue(ls.AttributeAvatar)
}

return &SearchResult{
LowerName: strings.ToLower(username),
Username: username,
Expand All @@ -372,6 +382,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
SSHPublicKey: sshPublicKey,
IsAdmin: isAdmin,
IsRestricted: isRestricted,
Avatar: Avatar,
}
}

Expand Down Expand Up @@ -403,14 +414,18 @@ func (ls *Source) SearchEntries() ([]*SearchResult, error) {

userFilter := fmt.Sprintf(ls.Filter, "*")

var isAttributeSSHPublicKeySet = len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
isAttributeSSHPublicKeySet := len(strings.TrimSpace(ls.AttributeSSHPublicKey)) > 0
isAtributeAvatarSet := len(strings.TrimSpace(ls.AttributeAvatar)) > 0

attribs := []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}
if isAttributeSSHPublicKeySet {
attribs = append(attribs, ls.AttributeSSHPublicKey)
}
if isAtributeAvatarSet {
attribs = append(attribs, ls.AttributeAvatar)
}

log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, ls.UserBase)
log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, ls.AttributeAvatar, userFilter, ls.UserBase)
search := ldap.NewSearchRequest(
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
attribs, nil)
Expand Down Expand Up @@ -442,8 +457,10 @@ func (ls *Source) SearchEntries() ([]*SearchResult, error) {
if isAttributeSSHPublicKeySet {
result[i].SSHPublicKey = v.GetAttributeValues(ls.AttributeSSHPublicKey)
}
if isAtributeAvatarSet {
result[i].Avatar = v.GetRawAttributeValue(ls.AttributeAvatar)
}
result[i].LowerName = strings.ToLower(result[i].Username)

}

return result, nil
Expand Down
Loading

0 comments on commit 3852ca4

Please sign in to comment.