diff --git a/AUTHORS b/AUTHORS index 70a75464bb..553a2ece75 100644 --- a/AUTHORS +++ b/AUTHORS @@ -63,3 +63,4 @@ List of contributors, in chronological order: * Ramón N.Rodriguez (https://github.com/runitonmetal) * Golf Hu (https://github.com/hudeng-go) * Cookie Fei (https://github.com/wuhuang26) +* Brett Hawn (https://github.com/bpiraeus) diff --git a/api/auth.go b/api/auth.go new file mode 100644 index 0000000000..1a1827de03 --- /dev/null +++ b/api/auth.go @@ -0,0 +1,118 @@ +package api + +import ( + "crypto/tls" + "fmt" + "strings" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "github.com/go-ldap/ldap/v3" +) + +func Authorize(username string, password string) (ok bool) { + config := context.Config() + + if config.Auth.Type != "" { + switch strings.ToLower(config.Auth.Type) { + case "ldap": + ok = doLdapAuth(username, password) + default: + return false + } + if !ok { + return false + } + } + return true +} + +func doLdapAuth(username string, password string) bool { + config := context.Config() + attributes := []string{"DN", "CN"} + + server := config.Auth.Server + dn := config.Auth.LdapDN + filter := fmt.Sprintf(config.Auth.LdapFilter, username) + + // connect to ldap server + conn, err := ldap.Dial("tcp", server) + if err != nil { + return false + } + defer conn.Close() + + // reconnect via tls + err = conn.StartTLS(&tls.Config{InsecureSkipVerify: config.Auth.SecureTLS}) + if err != nil { + return false + } + + // format our request and then fire it off + request := ldap.NewSearchRequest(dn, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, attributes, nil) + search, err := conn.Search(request) + if err != nil { + return false + } + // get our modified dn and then check our user for auth + udn := search.Entries[0].DN + err = conn.Bind(udn, password) + if err != nil { + return false + } + return true +} + +func getGroups(c *gin.Context, username string) { + + var groups []string + config := context.Config() + dn := config.Auth.LdapDN + session := sessions.Default(c) + // connect to ldap server + server := fmt.Sprintf("%s", config.Auth.Server) + conn, err := ldap.Dial("tcp", server) + if err != nil { + return + } + // reconnect via tls + err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true}) + if err != nil { + return + } + filter := fmt.Sprintf("(|(member=uid=%s,ou=people,dc=llnw,dc=com)(member=uid=%s,ou=people,dc=llnw,dc=com))", username, username) + request := ldap.NewSearchRequest(dn, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"dn", "cn"}, nil) + search, err := conn.Search(request) + if err != nil { + return + } + if len(search.Entries) < 1 { + return + } + for _, v := range search.Entries { + value := strings.Split(strings.TrimLeft(v.DN, "cn="), ",")[0] + groups = append(groups, fmt.Sprintf("%s,", value)) + } + session.Set("Groups", groups) +} + +func checkGroup(c *gin.Context, ldgroup string) bool { + session := sessions.Default(c) + groups := session.Get("Groups") + if ldgroup == "" { + return true + } + for _, v := range groups.([]string) { + if strings.Contains(v, ldgroup) { + return true + } + } + return false +} + +func CheckGroup(c *gin.Context, ldgroup string) (err error) { + if !checkGroup(c, ldgroup) { + err = fmt.Errorf("Authorisation Failred") + } + return err +} diff --git a/api/publish.go b/api/publish.go index a434d90cb6..8cb20c14f5 100644 --- a/api/publish.go +++ b/api/publish.go @@ -169,6 +169,11 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { return } + err = CheckGroup(c, localRepo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + } + resources = append(resources, string(localRepo.Key())) err = localCollection.LoadComplete(localRepo) if err != nil { diff --git a/api/repos.go b/api/repos.go index 81425f999b..7ba0ec5e89 100644 --- a/api/repos.go +++ b/api/repos.go @@ -87,6 +87,7 @@ func apiReposCreate(c *gin.Context) { Comment string DefaultDistribution string DefaultComponent string + LdapGroup string } if c.Bind(&b) != nil { @@ -96,6 +97,7 @@ func apiReposCreate(c *gin.Context) { repo := deb.NewLocalRepo(b.Name, b.Comment) repo.DefaultComponent = b.DefaultComponent repo.DefaultDistribution = b.DefaultDistribution + repo.LdapGroup = b.LdapGroup collectionFactory := context.NewCollectionFactory() collection := collectionFactory.LocalRepoCollection() @@ -115,6 +117,7 @@ func apiReposEdit(c *gin.Context) { Comment *string DefaultDistribution *string DefaultComponent *string + LdapGroup *string } if c.Bind(&b) != nil { @@ -130,6 +133,12 @@ func apiReposEdit(c *gin.Context) { return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } + if b.Name != nil { _, err := collection.ByName(*b.Name) if err == nil { @@ -148,6 +157,9 @@ func apiReposEdit(c *gin.Context) { if b.DefaultComponent != nil { repo.DefaultComponent = *b.DefaultComponent } + if b.LdapGroup != nil { + repo.LdapGroup = *b.LdapGroup + } err = collection.Update(repo) if err != nil { @@ -196,6 +208,12 @@ func apiReposDrop(c *gin.Context) { return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } + resources := []string{string(repo.Key())} taskName := fmt.Sprintf("Delete repo %s", name) maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { @@ -260,6 +278,12 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } + resources := []string{string(repo.Key())} maybeRunTaskInBackground(c, taskNamePrefix+repo.Name, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { out.Printf("Loading packages...\n") @@ -366,6 +390,12 @@ func apiReposPackageFromDir(c *gin.Context) { return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } + var taskName string var sources []string if fileParam == "" { @@ -651,6 +681,11 @@ func apiReposIncludePackageFromDir(c *gin.Context) { AbortWithJSONError(c, 404, err) return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } resources = append(resources, string(repo.Key())) } diff --git a/api/router.go b/api/router.go index d5b6e61232..8f610d6d45 100644 --- a/api/router.go +++ b/api/router.go @@ -1,9 +1,12 @@ package api import ( + "fmt" + "log" "net/http" "os" "sync/atomic" + "time" "github.com/aptly-dev/aptly/aptly" ctx "github.com/aptly-dev/aptly/context" @@ -11,10 +14,13 @@ import ( "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/zerolog/log" - _ "github.com/aptly-dev/aptly/docs" // import docs swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + "github.com/gin-gonic/gin" + uuid "github.com/nu7hatch/gouuid" ) var context *ctx.AptlyContext @@ -134,99 +140,160 @@ func Router(c *ctx.AptlyContext) http.Handler { api.GET("/healthy", apiHealthy) } + // set up cookies and sessions + token, err := uuid.NewV4() + if err != nil { + panic(err) + } + + store := cookie.NewStore([]byte(token.String())) + router.Use(sessions.Sessions(token.String(), store)) + // prep our config fetcher ahead of need + config := context.Config() + + // prep a logfile if we've set one + if config.LogFile != "" { + file, err := os.OpenFile(config.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } + defer file.Close() + log.SetOutput(file) + } + + router.GET("/version", apiVersion) + + var username string + var password string + router.POST("/login", func(c *gin.Context) { + session := sessions.Default(c) + session.Options(sessions.Options{MaxAge: 30}) + if config.UseAuth { + log.Printf("UseAuth is enabled\n") + username = c.PostForm("username") + password = c.PostForm("password") + if !Authorize(username, password) { + c.AbortWithError(403, fmt.Errorf("Authorization Failure")) + } + log.Printf("%s authorized from %s\n", username, c.ClientIP()) + } + session.Set(token.String(), time.Now().Unix()) + session.Save() + getGroups(c, username) + c.String(200, "Authorized!") + }) + + router.POST("/logout", func(c *gin.Context) { + session := sessions.Default(c) + session.Options(sessions.Options{MaxAge: -1}) + session.Save() + c.String(200, "Deauthorized") + }) + + authorize := router.Group("/api", func(c *gin.Context) { + session := sessions.Default(c) + if config.UseAuth { + if session.Get(token.String()) == nil { + c.AbortWithError(403, fmt.Errorf("not authorized")) + } + session.Options(sessions.Options{MaxAge: 30}) + session.Set(token.String(), time.Now().Unix()) + session.Save() + } + }) + { - api.GET("/repos", apiReposList) - api.POST("/repos", apiReposCreate) - api.GET("/repos/:name", apiReposShow) - api.PUT("/repos/:name", apiReposEdit) - api.DELETE("/repos/:name", apiReposDrop) + authorize.GET("/repos", apiReposList) + authorize.POST("/repos", apiReposCreate) + authorize.GET("/repos/:name", apiReposShow) + authorize.PUT("/repos/:name", apiReposEdit) + authorize.DELETE("/repos/:name", apiReposDrop) - api.GET("/repos/:name/packages", apiReposPackagesShow) - api.POST("/repos/:name/packages", apiReposPackagesAdd) - api.DELETE("/repos/:name/packages", apiReposPackagesDelete) + authorize.GET("/repos/:name/packages", apiReposPackagesShow) + authorize.POST("/repos/:name/packages", apiReposPackagesAdd) + authorize.DELETE("/repos/:name/packages", apiReposPackagesDelete) - api.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile) - api.POST("/repos/:name/file/:dir", apiReposPackageFromDir) - api.POST("/repos/:name/copy/:src/:file", apiReposCopyPackage) + authorize.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile) + authorize.POST("/repos/:name/file/:dir", apiReposPackageFromDir) + authorize.POST("/repos/:name/copy/:src/:file", apiReposCopyPackage) - api.POST("/repos/:name/include/:dir/:file", apiReposIncludePackageFromFile) - api.POST("/repos/:name/include/:dir", apiReposIncludePackageFromDir) + authorize.POST("/repos/:name/include/:dir/:file", apiReposIncludePackageFromFile) + authorize.POST("/repos/:name/include/:dir", apiReposIncludePackageFromDir) - api.POST("/repos/:name/snapshots", apiSnapshotsCreateFromRepository) + authorize.POST("/repos/:name/snapshots", apiSnapshotsCreateFromRepository) } { - api.POST("/mirrors/:name/snapshots", apiSnapshotsCreateFromMirror) + authorize.POST("/mirrors/:name/snapshots", apiSnapshotsCreateFromMirror) } { - api.GET("/mirrors", apiMirrorsList) - api.GET("/mirrors/:name", apiMirrorsShow) - api.GET("/mirrors/:name/packages", apiMirrorsPackages) - api.POST("/mirrors", apiMirrorsCreate) - api.PUT("/mirrors/:name", apiMirrorsUpdate) - api.DELETE("/mirrors/:name", apiMirrorsDrop) + authorize.GET("/mirrors", apiMirrorsList) + authorize.GET("/mirrors/:name", apiMirrorsShow) + authorize.GET("/mirrors/:name/packages", apiMirrorsPackages) + authorize.POST("/mirrors", apiMirrorsCreate) + authorize.PUT("/mirrors/:name", apiMirrorsUpdate) + authorize.DELETE("/mirrors/:name", apiMirrorsDrop) } { - api.POST("/gpg/key", apiGPGAddKey) + authorize.POST("/gpg/key", apiGPGAddKey) } { - api.GET("/s3", apiS3List) + authorize.GET("/s3", apiS3List) } { - api.GET("/files", apiFilesListDirs) - api.POST("/files/:dir", apiFilesUpload) - api.GET("/files/:dir", apiFilesListFiles) - api.DELETE("/files/:dir", apiFilesDeleteDir) - api.DELETE("/files/:dir/:name", apiFilesDeleteFile) + authorize.GET("/files", apiFilesListDirs) + authorize.POST("/files/:dir", apiFilesUpload) + authorize.GET("/files/:dir", apiFilesListFiles) + authorize.DELETE("/files/:dir", apiFilesDeleteDir) + authorize.DELETE("/files/:dir/:name", apiFilesDeleteFile) } { - - api.GET("/publish", apiPublishList) - api.POST("/publish", apiPublishRepoOrSnapshot) - api.POST("/publish/:prefix", apiPublishRepoOrSnapshot) - api.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) - api.DELETE("/publish/:prefix/:distribution", apiPublishDrop) + authorize.GET("/publish", apiPublishList) + authorize.POST("/publish", apiPublishRepoOrSnapshot) + authorize.POST("/publish/:prefix", apiPublishRepoOrSnapshot) + authorize.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) + authorize.DELETE("/publish/:prefix/:distribution", apiPublishDrop) } { - api.GET("/snapshots", apiSnapshotsList) - api.POST("/snapshots", apiSnapshotsCreate) - api.PUT("/snapshots/:name", apiSnapshotsUpdate) - api.GET("/snapshots/:name", apiSnapshotsShow) - api.GET("/snapshots/:name/packages", apiSnapshotsSearchPackages) - api.DELETE("/snapshots/:name", apiSnapshotsDrop) - api.GET("/snapshots/:name/diff/:withSnapshot", apiSnapshotsDiff) - api.POST("/snapshots/:name/merge", apiSnapshotsMerge) - api.POST("/snapshots/:name/pull", apiSnapshotsPull) + authorize.GET("/snapshots", apiSnapshotsList) + authorize.POST("/snapshots", apiSnapshotsCreate) + authorize.PUT("/snapshots/:name", apiSnapshotsUpdate) + authorize.GET("/snapshots/:name", apiSnapshotsShow) + authorize.GET("/snapshots/:name/packages", apiSnapshotsSearchPackages) + authorize.DELETE("/snapshots/:name", apiSnapshotsDrop) + authorize.GET("/snapshots/:name/diff/:withSnapshot", apiSnapshotsDiff) + authorize.POST("/snapshots/:name/merge", apiSnapshotsMerge) + authorize.POST("/snapshots/:name/pull", apiSnapshotsPull) } { - api.GET("/packages/:key", apiPackagesShow) - api.GET("/packages", apiPackages) + authorize.GET("/packages/:key", apiPackagesShow) + authorize.GET("/packages", apiPackages) } { - api.GET("/graph.:ext", apiGraph) + authorize.GET("/graph.:ext", apiGraph) } { - api.POST("/db/cleanup", apiDbCleanup) + authorize.POST("/db/cleanup", apiDbCleanup) } { - api.GET("/tasks", apiTasksList) - api.POST("/tasks-clear", apiTasksClear) - api.GET("/tasks-wait", apiTasksWait) - api.GET("/tasks/:id/wait", apiTasksWaitForTaskByID) - api.GET("/tasks/:id/output", apiTasksOutputShow) - api.GET("/tasks/:id/detail", apiTasksDetailShow) - api.GET("/tasks/:id/return_value", apiTasksReturnValueShow) - api.GET("/tasks/:id", apiTasksShow) - api.DELETE("/tasks/:id", apiTasksDelete) - api.POST("/tasks-dummy", apiTasksDummy) + authorize.GET("/tasks", apiTasksList) + authorize.POST("/tasks-clear", apiTasksClear) + authorize.GET("/tasks-wait", apiTasksWait) + authorize.GET("/tasks/:id/wait", apiTasksWaitForTaskByID) + authorize.GET("/tasks/:id/output", apiTasksOutputShow) + authorize.GET("/tasks/:id/detail", apiTasksDetailShow) + authorize.GET("/tasks/:id/return_value", apiTasksReturnValueShow) + authorize.GET("/tasks/:id", apiTasksShow) + authorize.DELETE("/tasks/:id", apiTasksDelete) + authorize.POST("/tasks-dummy", apiTasksDummy) } return router diff --git a/api/snapshot.go b/api/snapshot.go index 3e84b1f202..6e09ac70d7 100644 --- a/api/snapshot.go +++ b/api/snapshot.go @@ -200,6 +200,12 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) { return } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + return + } + // including snapshot resource key resources := []string{string(repo.Key()), "S" + b.Name} taskName := fmt.Sprintf("Create snapshot of repo %s", name) diff --git a/cmd/repo_create.go b/cmd/repo_create.go index 5fef46d922..716c879628 100644 --- a/cmd/repo_create.go +++ b/cmd/repo_create.go @@ -18,6 +18,7 @@ func aptlyRepoCreate(cmd *commander.Command, args []string) error { repo := deb.NewLocalRepo(args[0], context.Flags().Lookup("comment").Value.String()) repo.DefaultDistribution = context.Flags().Lookup("distribution").Value.String() repo.DefaultComponent = context.Flags().Lookup("component").Value.String() + repo.LdapGroup = context.Flags().Lookup("ldap-group").Value.String() uploadersFile := context.Flags().Lookup("uploaders-file").Value.Get().(string) if uploadersFile != "" { @@ -79,6 +80,7 @@ Example: cmd.Flag.String("distribution", "", "default distribution when publishing") cmd.Flag.String("component", "main", "default component when publishing") cmd.Flag.String("uploaders-file", "", "uploaders.json to be used when including .changes into this repository") + cmd.Flag.String("ldap-group", "", "ldap group that owns the repo, leave empty to allow ALL") return cmd } diff --git a/cmd/repo_edit.go b/cmd/repo_edit.go index bc81dc4a12..30d29f3683 100644 --- a/cmd/repo_edit.go +++ b/cmd/repo_edit.go @@ -39,6 +39,8 @@ func aptlyRepoEdit(cmd *commander.Command, args []string) error { repo.DefaultComponent = flag.Value.String() case "uploaders-file": uploadersFile = pointer.ToString(flag.Value.String()) + case "ldap-group": + repo.LdapGroup = flag.Value.String() } }) @@ -82,6 +84,7 @@ Example: cmd.Flag.String("distribution", "", "default distribution when publishing") cmd.Flag.String("component", "", "default component when publishing") cmd.Flag.String("uploaders-file", "", "uploaders.json to be used when including .changes into this repository") + cmd.Flag.String("ldap-group", "", "ldap group that owns the repo, leave empty to allow ALL") return cmd } diff --git a/cmd/repo_show.go b/cmd/repo_show.go index a61a5f1f92..07765281d9 100644 --- a/cmd/repo_show.go +++ b/cmd/repo_show.go @@ -45,6 +45,7 @@ func aptlyRepoShowTxt(_ *commander.Command, args []string) error { fmt.Printf("Comment: %s\n", repo.Comment) fmt.Printf("Default Distribution: %s\n", repo.DefaultDistribution) fmt.Printf("Default Component: %s\n", repo.DefaultComponent) + fmt.Printf("Ldap Group: %s\n", repo.LdapGroup) if repo.Uploaders != nil { fmt.Printf("Uploaders: %s\n", repo.Uploaders) } diff --git a/completion.d/_aptly b/completion.d/_aptly index 8e8d2bbd65..3d8d19e63b 100644 --- a/completion.d/_aptly +++ b/completion.d/_aptly @@ -242,6 +242,7 @@ local keyring="*-keyring=[gpg keyring to use when verifying Release file (could local create_edit=("-comment=[any text that would be used to described local repository]:comment: " "-component=[default component when publishing]:component:($components)" "-distribution=[default distribution when publishing]:distribution:($dists)" + "-ldap-group=[ldap group for repo actions, empty by default]:ldap-group" $aptly_uploaders ) diff --git a/deb/local.go b/deb/local.go index 1b09fdbda3..0fa10fa81b 100644 --- a/deb/local.go +++ b/deb/local.go @@ -27,6 +27,8 @@ type LocalRepo struct { Uploaders *Uploaders `codec:"Uploaders,omitempty" json:"-"` // "Snapshot" of current list of packages packageRefs *PackageRefList + // ldap group for repos + LdapGroup string `codec:",ldap-group"` } // NewLocalRepo creates new instance of Debian local repository @@ -54,6 +56,14 @@ func (repo *LocalRepo) NumPackages() int { return repo.packageRefs.Len() } +// LdapGroup returns the ldapgroup if any for the repo +func (repo *LocalRepo) GetLDGroup() string { + if repo.LdapGroup != "" { + return fmt.Sprintf("[%s]", repo.LdapGroup) + } + return "" +} + // RefList returns package list for repo func (repo *LocalRepo) RefList() *PackageRefList { return repo.packageRefs diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index baab5ff6b6..2c4ab4f9b7 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -113,7 +113,14 @@ Configuration file is stored in JSON format (default values shown below): "prefix": "", "endpoint": "" } - } + }, + "Auth": { + "authType: "", + "server\": "", + "ldapDN\": "", + "ldapFilter": "", + "secureTLS": false + } } Options: @@ -207,6 +214,9 @@ Options: * `AzurePublishEndpoints`: configuration of Azure publishing endpoints (see below) + * `Auth`: + configuration of authorization for repos, only supports ldap at this time (see below) + ## CUSTOM PACKAGE POOLS aptly defaults to storing downloaded packages at `rootDir/`pool. In order to @@ -220,6 +230,7 @@ two values: keys in the below section on Azure publishing may be set on the `packagePoolStorage` object in order to configure the Azure connection. + ## FILESYSTEM PUBLISHING ENDPOINTS aptly defaults to publish to a single publish directory under `rootDir`/public. For @@ -348,6 +359,26 @@ configuration file. Each endpoint has its name and associated settings: [the Azure documentation](https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string); defaults to `https://$accountName.blob.core.windows.net` +## AUTH ENDPOINTS + +Authorization for repos may be configured for ldap groups (and is extensible for others), +default is no authorization. + + * `authType`: + auth type, only supports ldap currently + + * `server`: + auth server to use (eg. ldaps://ldap.example.com) + + * `ldapDN`: + DN for ldap searches + + * `ldapFilter: + ldap filter + + * `secureTLS`: + enable secureTLS, default is off + ## PACKAGE QUERY Some commands accept package queries to identify list of packages to process. diff --git a/utils/config.go b/utils/config.go index b25ba4ea55..c625eb7622 100644 --- a/utils/config.go +++ b/utils/config.go @@ -11,6 +11,8 @@ import ( // ConfigStructure is structure of main configuration type ConfigStructure struct { // nolint: maligned RootDir string `json:"rootDir"` + LogFile string `json:"logFile"` + UseAuth bool `json:"useAuth"` DownloadConcurrency int `json:"downloadConcurrency"` DownloadLimit int64 `json:"downloadSpeedLimit"` DownloadRetries int `json:"downloadRetries"` @@ -43,6 +45,7 @@ type ConfigStructure struct { // nolint: maligned ServeInAPIMode bool `json:"serveInAPIMode"` DatabaseBackend DBConfig `json:"databaseBackend"` EnableSwaggerEndpoint bool `json:"enableSwaggerEndpoint"` + Auth AAuth `json:"Auth"` } // DBConfig @@ -150,9 +153,19 @@ type AzureEndpoint struct { Endpoint string `json:"endpoint"` } +type AAuth struct { + Type string `json:"authType"` + Server string `json:"server"` + LdapDN string `json:"ldapDN"` + LdapFilter string `json:"ldapFilter"` + SecureTLS bool `json:"secureTLS"` +} + // Config is configuration for aptly, shared by all modules var Config = ConfigStructure{ RootDir: filepath.Join(os.Getenv("HOME"), ".aptly"), + LogFile: "", + UseAuth: false, // should we enable auth DownloadConcurrency: 4, DownloadLimit: 0, Downloader: "default", @@ -182,6 +195,7 @@ var Config = ConfigStructure{ LogFormat: "default", ServeInAPIMode: false, EnableSwaggerEndpoint: false, + Auth: AAuth{}, } // LoadConfig loads configuration from json file diff --git a/utils/config_test.go b/utils/config_test.go index badff76992..513c01d827 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -65,6 +65,8 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { c.Check(string(buf), Equals, ""+ "{\n"+ " \"rootDir\": \"/tmp/aptly\",\n"+ + " \"logFile\": \"\",\n"+ + " \"useAuth\": false,\n"+ " \"downloadConcurrency\": 5,\n"+ " \"downloadSpeedLimit\": 0,\n"+ " \"downloadRetries\": 0,\n"+ @@ -149,7 +151,14 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"url\": \"\",\n"+ " \"dbPath\": \"\"\n" + " },\n"+ - " \"enableSwaggerEndpoint\": false\n" + + " \"enableSwaggerEndpoint\": false,\n" + + " \"Auth\": {\n"+ + " \"authType\": \"\",\n"+ + " \"server\": \"\",\n"+ + " \"ldapDN\": \"\",\n"+ + " \"ldapFilter\": \"\",\n"+ + " \"secureTLS\": false\n"+ + " }\n"+ "}") }