2019-06-17 21:32:20 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2019-06-17 21:32:20 +03:00
package cmd
import (
2021-11-07 06:11:27 +03:00
"context"
2019-06-17 21:32:20 +03:00
"fmt"
"strings"
2022-01-02 16:12:35 +03:00
"code.gitea.io/gitea/models/auth"
2021-07-24 13:16:34 +03:00
"code.gitea.io/gitea/services/auth/source/ldap"
2019-06-17 21:32:20 +03:00
2023-07-21 12:28:19 +03:00
"github.com/urfave/cli/v2"
2019-06-17 21:32:20 +03:00
)
type (
authService struct {
2022-01-02 16:12:35 +03:00
initDB func ( ctx context . Context ) error
2023-10-11 07:24:07 +03:00
createAuthSource func ( context . Context , * auth . Source ) error
updateAuthSource func ( context . Context , * auth . Source ) error
getAuthSourceByID func ( ctx context . Context , id int64 ) ( * auth . Source , error )
2019-06-17 21:32:20 +03:00
}
)
var (
commonLdapCLIFlags = [ ] cli . Flag {
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "name" ,
Usage : "Authentication name." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2019-06-17 21:32:20 +03:00
Name : "not-active" ,
Usage : "Deactivate the authentication source." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2022-07-04 12:21:14 +03:00
Name : "active" ,
Usage : "Activate the authentication source." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "security-protocol" ,
Usage : "Security protocol name." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2019-06-17 21:32:20 +03:00
Name : "skip-tls-verify" ,
Usage : "Disable TLS verification." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "host" ,
Usage : "The address where the LDAP server can be reached." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . IntFlag {
2019-06-17 21:32:20 +03:00
Name : "port" ,
Usage : "The port to use when connecting to the LDAP server." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "user-search-base" ,
Usage : "The LDAP base at which user accounts will be searched for." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "user-filter" ,
Usage : "An LDAP filter declaring how to find the user record that is attempting to authenticate." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "admin-filter" ,
Usage : "An LDAP filter specifying if a user should be given administrator privileges." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2020-03-05 09:30:33 +03:00
Name : "restricted-filter" ,
Usage : "An LDAP filter specifying if a user should be given restricted status." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2020-01-20 06:47:39 +03:00
Name : "allow-deactivate-all" ,
Usage : "Allow empty search results to deactivate all users." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "username-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user name." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "firstname-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user’ s first name." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "surname-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user’ s surname." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "email-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user’ s email address." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "public-ssh-key-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user’ s public ssh key." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2021-09-17 14:43:47 +03:00
Name : "skip-local-2fa" ,
Usage : "Set to true to skip local 2fa for users authenticated by this source" ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2021-09-27 05:39:36 +03:00
Name : "avatar-attribute" ,
Usage : "The attribute of the user’ s LDAP record containing the user’ s avatar." ,
} ,
2019-06-17 21:32:20 +03:00
}
ldapBindDnCLIFlags = append ( commonLdapCLIFlags ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "bind-dn" ,
Usage : "The DN to bind to the LDAP server with when searching for the user." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "bind-password" ,
Usage : "The password for the Bind DN, if any." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2019-06-17 21:32:20 +03:00
Name : "attributes-in-bind" ,
Usage : "Fetch attributes in bind DN context." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2019-06-17 21:32:20 +03:00
Name : "synchronize-users" ,
Usage : "Enable user synchronization." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . BoolFlag {
2022-07-04 12:21:14 +03:00
Name : "disable-synchronize-users" ,
Usage : "Disable user synchronization." ,
} ,
2023-07-21 12:28:19 +03:00
& cli . UintFlag {
2019-06-17 21:32:20 +03:00
Name : "page-size" ,
Usage : "Search page size." ,
} )
ldapSimpleAuthCLIFlags = append ( commonLdapCLIFlags ,
2023-07-21 12:28:19 +03:00
& cli . StringFlag {
2019-06-17 21:32:20 +03:00
Name : "user-dn" ,
2023-09-27 15:25:38 +03:00
Usage : "The user's DN." ,
2019-06-17 21:32:20 +03:00
} )
2023-09-27 15:25:38 +03:00
microcmdAuthAddLdapBindDn = & cli . Command {
2019-06-17 21:32:20 +03:00
Name : "add-ldap" ,
Usage : "Add new LDAP (via Bind DN) authentication source" ,
Action : func ( c * cli . Context ) error {
return newAuthService ( ) . addLdapBindDn ( c )
} ,
Flags : ldapBindDnCLIFlags ,
}
2023-09-27 15:25:38 +03:00
microcmdAuthUpdateLdapBindDn = & cli . Command {
2019-06-17 21:32:20 +03:00
Name : "update-ldap" ,
Usage : "Update existing LDAP (via Bind DN) authentication source" ,
Action : func ( c * cli . Context ) error {
return newAuthService ( ) . updateLdapBindDn ( c )
} ,
Flags : append ( [ ] cli . Flag { idFlag } , ldapBindDnCLIFlags ... ) ,
}
2023-09-27 15:25:38 +03:00
microcmdAuthAddLdapSimpleAuth = & cli . Command {
2019-06-17 21:32:20 +03:00
Name : "add-ldap-simple" ,
Usage : "Add new LDAP (simple auth) authentication source" ,
Action : func ( c * cli . Context ) error {
return newAuthService ( ) . addLdapSimpleAuth ( c )
} ,
Flags : ldapSimpleAuthCLIFlags ,
}
2023-09-27 15:25:38 +03:00
microcmdAuthUpdateLdapSimpleAuth = & cli . Command {
2019-06-17 21:32:20 +03:00
Name : "update-ldap-simple" ,
Usage : "Update existing LDAP (simple auth) authentication source" ,
Action : func ( c * cli . Context ) error {
return newAuthService ( ) . updateLdapSimpleAuth ( c )
} ,
Flags : append ( [ ] cli . Flag { idFlag } , ldapSimpleAuthCLIFlags ... ) ,
}
)
// newAuthService creates a service with default functions.
func newAuthService ( ) * authService {
return & authService {
2022-01-02 16:12:35 +03:00
initDB : initDB ,
createAuthSource : auth . CreateSource ,
updateAuthSource : auth . UpdateSource ,
getAuthSourceByID : auth . GetSourceByID ,
2019-06-17 21:32:20 +03:00
}
}
2022-01-02 16:12:35 +03:00
// parseAuthSource assigns values on authSource according to command line flags.
func parseAuthSource ( c * cli . Context , authSource * auth . Source ) {
2019-06-17 21:32:20 +03:00
if c . IsSet ( "name" ) {
2022-01-02 16:12:35 +03:00
authSource . Name = c . String ( "name" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "not-active" ) {
2022-01-02 16:12:35 +03:00
authSource . IsActive = ! c . Bool ( "not-active" )
2019-06-17 21:32:20 +03:00
}
2022-07-04 12:21:14 +03:00
if c . IsSet ( "active" ) {
authSource . IsActive = c . Bool ( "active" )
}
2019-06-17 21:32:20 +03:00
if c . IsSet ( "synchronize-users" ) {
2022-01-02 16:12:35 +03:00
authSource . IsSyncEnabled = c . Bool ( "synchronize-users" )
2019-06-17 21:32:20 +03:00
}
2022-07-04 12:21:14 +03:00
if c . IsSet ( "disable-synchronize-users" ) {
authSource . IsSyncEnabled = ! c . Bool ( "disable-synchronize-users" )
}
2019-06-17 21:32:20 +03:00
}
// parseLdapConfig assigns values on config according to command line flags.
2021-07-24 13:16:34 +03:00
func parseLdapConfig ( c * cli . Context , config * ldap . Source ) error {
2019-06-17 21:32:20 +03:00
if c . IsSet ( "name" ) {
2021-07-24 13:16:34 +03:00
config . Name = c . String ( "name" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "host" ) {
2021-07-24 13:16:34 +03:00
config . Host = c . String ( "host" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "port" ) {
2021-07-24 13:16:34 +03:00
config . Port = c . Int ( "port" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "security-protocol" ) {
p , ok := findLdapSecurityProtocolByName ( c . String ( "security-protocol" ) )
if ! ok {
return fmt . Errorf ( "Unknown security protocol name: %s" , c . String ( "security-protocol" ) )
}
2021-07-24 13:16:34 +03:00
config . SecurityProtocol = p
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "skip-tls-verify" ) {
2021-07-24 13:16:34 +03:00
config . SkipVerify = c . Bool ( "skip-tls-verify" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "bind-dn" ) {
2021-07-24 13:16:34 +03:00
config . BindDN = c . String ( "bind-dn" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "user-dn" ) {
2021-07-24 13:16:34 +03:00
config . UserDN = c . String ( "user-dn" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "bind-password" ) {
2021-07-24 13:16:34 +03:00
config . BindPassword = c . String ( "bind-password" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "user-search-base" ) {
2021-07-24 13:16:34 +03:00
config . UserBase = c . String ( "user-search-base" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "username-attribute" ) {
2021-07-24 13:16:34 +03:00
config . AttributeUsername = c . String ( "username-attribute" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "firstname-attribute" ) {
2021-07-24 13:16:34 +03:00
config . AttributeName = c . String ( "firstname-attribute" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "surname-attribute" ) {
2021-07-24 13:16:34 +03:00
config . AttributeSurname = c . String ( "surname-attribute" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "email-attribute" ) {
2021-07-24 13:16:34 +03:00
config . AttributeMail = c . String ( "email-attribute" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "attributes-in-bind" ) {
2021-07-24 13:16:34 +03:00
config . AttributesInBind = c . Bool ( "attributes-in-bind" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "public-ssh-key-attribute" ) {
2021-07-24 13:16:34 +03:00
config . AttributeSSHPublicKey = c . String ( "public-ssh-key-attribute" )
2019-06-17 21:32:20 +03:00
}
2021-09-27 05:39:36 +03:00
if c . IsSet ( "avatar-attribute" ) {
config . AttributeAvatar = c . String ( "avatar-attribute" )
}
2019-06-17 21:32:20 +03:00
if c . IsSet ( "page-size" ) {
2021-07-24 13:16:34 +03:00
config . SearchPageSize = uint32 ( c . Uint ( "page-size" ) )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "user-filter" ) {
2021-07-24 13:16:34 +03:00
config . Filter = c . String ( "user-filter" )
2019-06-17 21:32:20 +03:00
}
if c . IsSet ( "admin-filter" ) {
2021-07-24 13:16:34 +03:00
config . AdminFilter = c . String ( "admin-filter" )
2019-06-17 21:32:20 +03:00
}
2020-03-05 09:30:33 +03:00
if c . IsSet ( "restricted-filter" ) {
2021-07-24 13:16:34 +03:00
config . RestrictedFilter = c . String ( "restricted-filter" )
2020-03-05 09:30:33 +03:00
}
2020-01-20 06:47:39 +03:00
if c . IsSet ( "allow-deactivate-all" ) {
2021-07-24 13:16:34 +03:00
config . AllowDeactivateAll = c . Bool ( "allow-deactivate-all" )
2020-01-20 06:47:39 +03:00
}
2021-09-17 14:43:47 +03:00
if c . IsSet ( "skip-local-2fa" ) {
config . SkipLocalTwoFA = c . Bool ( "skip-local-2fa" )
}
2019-06-17 21:32:20 +03:00
return nil
}
// findLdapSecurityProtocolByName finds security protocol by its name ignoring case.
// It returns the value of the security protocol and if it was found.
func findLdapSecurityProtocolByName ( name string ) ( ldap . SecurityProtocol , bool ) {
2021-07-24 13:16:34 +03:00
for i , n := range ldap . SecurityProtocolNames {
2019-06-17 21:32:20 +03:00
if strings . EqualFold ( name , n ) {
return i , true
}
}
return 0 , false
}
2022-01-02 16:12:35 +03:00
// getAuthSource gets the login source by its id defined in the command line flags.
2019-06-17 21:32:20 +03:00
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
2023-10-11 07:24:07 +03:00
func ( a * authService ) getAuthSource ( ctx context . Context , c * cli . Context , authType auth . Type ) ( * auth . Source , error ) {
2019-06-17 21:32:20 +03:00
if err := argsSet ( c , "id" ) ; err != nil {
return nil , err
}
2023-10-11 07:24:07 +03:00
authSource , err := a . getAuthSourceByID ( ctx , c . Int64 ( "id" ) )
2019-06-17 21:32:20 +03:00
if err != nil {
return nil , err
}
2022-01-02 16:12:35 +03:00
if authSource . Type != authType {
return nil , fmt . Errorf ( "Invalid authentication type. expected: %s, actual: %s" , authType . String ( ) , authSource . Type . String ( ) )
2019-06-17 21:32:20 +03:00
}
2022-01-02 16:12:35 +03:00
return authSource , nil
2019-06-17 21:32:20 +03:00
}
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
func ( a * authService ) addLdapBindDn ( c * cli . Context ) error {
if err := argsSet ( c , "name" , "security-protocol" , "host" , "port" , "user-search-base" , "user-filter" , "email-attribute" ) ; err != nil {
return err
}
2021-11-07 06:11:27 +03:00
ctx , cancel := installSignals ( )
defer cancel ( )
if err := a . initDB ( ctx ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2022-01-02 16:12:35 +03:00
authSource := & auth . Source {
Type : auth . LDAP ,
2021-07-24 13:16:34 +03:00
IsActive : true , // active by default
Cfg : & ldap . Source {
Enabled : true , // always true
2019-06-17 21:32:20 +03:00
} ,
}
2022-01-02 16:12:35 +03:00
parseAuthSource ( c , authSource )
if err := parseLdapConfig ( c , authSource . Cfg . ( * ldap . Source ) ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
return a . createAuthSource ( ctx , authSource )
2019-06-17 21:32:20 +03:00
}
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
func ( a * authService ) updateLdapBindDn ( c * cli . Context ) error {
2021-11-07 06:11:27 +03:00
ctx , cancel := installSignals ( )
defer cancel ( )
if err := a . initDB ( ctx ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
authSource , err := a . getAuthSource ( ctx , c , auth . LDAP )
2019-06-17 21:32:20 +03:00
if err != nil {
return err
}
2022-01-02 16:12:35 +03:00
parseAuthSource ( c , authSource )
if err := parseLdapConfig ( c , authSource . Cfg . ( * ldap . Source ) ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
return a . updateAuthSource ( ctx , authSource )
2019-06-17 21:32:20 +03:00
}
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
func ( a * authService ) addLdapSimpleAuth ( c * cli . Context ) error {
if err := argsSet ( c , "name" , "security-protocol" , "host" , "port" , "user-dn" , "user-filter" , "email-attribute" ) ; err != nil {
return err
}
2021-11-07 06:11:27 +03:00
ctx , cancel := installSignals ( )
defer cancel ( )
if err := a . initDB ( ctx ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2022-01-02 16:12:35 +03:00
authSource := & auth . Source {
Type : auth . DLDAP ,
2021-07-24 13:16:34 +03:00
IsActive : true , // active by default
Cfg : & ldap . Source {
Enabled : true , // always true
2019-06-17 21:32:20 +03:00
} ,
}
2022-01-02 16:12:35 +03:00
parseAuthSource ( c , authSource )
if err := parseLdapConfig ( c , authSource . Cfg . ( * ldap . Source ) ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
return a . createAuthSource ( ctx , authSource )
2019-06-17 21:32:20 +03:00
}
// updateLdapBindDn updates a new LDAP (simple auth) authentication source.
func ( a * authService ) updateLdapSimpleAuth ( c * cli . Context ) error {
2021-11-07 06:11:27 +03:00
ctx , cancel := installSignals ( )
defer cancel ( )
if err := a . initDB ( ctx ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
authSource , err := a . getAuthSource ( ctx , c , auth . DLDAP )
2019-06-17 21:32:20 +03:00
if err != nil {
return err
}
2022-01-02 16:12:35 +03:00
parseAuthSource ( c , authSource )
if err := parseLdapConfig ( c , authSource . Cfg . ( * ldap . Source ) ) ; err != nil {
2019-06-17 21:32:20 +03:00
return err
}
2023-10-11 07:24:07 +03:00
return a . updateAuthSource ( ctx , authSource )
2019-06-17 21:32:20 +03:00
}