diff --git a/AUTHORS b/AUTHORS index d62f1573..20884802 100644 --- a/AUTHORS +++ b/AUTHORS @@ -68,3 +68,4 @@ List of contributors, in chronological order: * Blake Kostner (https://github.com/btkostner) * Leigh London (https://github.com/leighlondon) * Gordian Schoenherr (https://github.com/schoenherrg) +* Brett Hawn (https://github.com/bpiraeus) diff --git a/api/auth.go b/api/auth.go new file mode 100644 index 00000000..4b28b5ef --- /dev/null +++ b/api/auth.go @@ -0,0 +1,119 @@ +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 != true { + 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 := fmt.Sprintf("%s", 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) + return +} + +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 e19afb17..bbabec71 100644 --- a/api/publish.go +++ b/api/publish.go @@ -267,7 +267,13 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { return } + err = CheckGroup(c, localRepo.LdapGroup) + if err != nil { + c.AbortWithError(403, err) + } + resources = append(resources, string(localRepo.Key())) + sources = append(sources, localRepo) } } else { diff --git a/api/repos.go b/api/repos.go index 4cc04f69..c9d025a7 100644 --- a/api/repos.go +++ b/api/repos.go @@ -95,6 +95,8 @@ type repoCreateParams struct { DefaultComponent string ` json:"DefaultComponent" example:"main"` // Snapshot name to create repoitory from (optional) FromSnapshot string ` json:"FromSnapshot" example:""` + // + LdapGroup string } // @Summary Create Repository @@ -125,6 +127,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() @@ -173,6 +176,8 @@ type reposEditParams struct { DefaultDistribution *string ` json:"DefaultDistribution" example:""` // Change Devault Component for publishing DefaultComponent *string ` json:"DefaultComponent" example:""` + // + LdapGroup *string } // @Summary Update Repository @@ -199,6 +204,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 { @@ -217,6 +228,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 { @@ -276,6 +290,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) { @@ -365,6 +385,11 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + return &task.ProcessReturnValue{Code: 403, Value: nil}, err + } + out.Printf("Loading packages...\n") list, err := deb.NewPackageListFromRefList(repo.RefList(), collectionFactory.PackageCollection(), nil) if err != nil { @@ -522,6 +547,11 @@ func apiReposPackageFromDir(c *gin.Context) { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err } + err = CheckGroup(c, repo.LdapGroup) + if err != nil { + return &task.ProcessReturnValue{Code: 403, Value: nil}, err + } + verifier := context.GetVerifier() var ( @@ -845,6 +875,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 3536ab09..49ef4e74 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" @@ -15,6 +18,10 @@ import ( "github.com/aptly-dev/aptly/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 @@ -133,105 +140,167 @@ 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.GET("/publish/:prefix/:distribution", apiPublishShow) - api.POST("/publish", apiPublishRepoOrSnapshot) - api.POST("/publish/:prefix", apiPublishRepoOrSnapshot) - api.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) - api.DELETE("/publish/:prefix/:distribution", apiPublishDrop) - api.POST("/publish/:prefix/:distribution/sources", apiPublishAddSource) - api.GET("/publish/:prefix/:distribution/sources", apiPublishListChanges) - api.PUT("/publish/:prefix/:distribution/sources", apiPublishSetSources) - api.DELETE("/publish/:prefix/:distribution/sources", apiPublishDropChanges) - api.PUT("/publish/:prefix/:distribution/sources/:component", apiPublishUpdateSource) - api.DELETE("/publish/:prefix/:distribution/sources/:component", apiPublishRemoveSource) - api.POST("/publish/:prefix/:distribution/update", apiPublishUpdate) + authorize.GET("/publish", apiPublishList) + authorize.GET("/publish/:prefix/:distribution", apiPublishShow) + authorize.POST("/publish", apiPublishRepoOrSnapshot) + authorize.POST("/publish/:prefix", apiPublishRepoOrSnapshot) + authorize.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) + authorize.DELETE("/publish/:prefix/:distribution", apiPublishDrop) + authorize.POST("/publish/:prefix/:distribution/sources", apiPublishAddSource) + authorize.GET("/publish/:prefix/:distribution/sources", apiPublishListChanges) + authorize.PUT("/publish/:prefix/:distribution/sources", apiPublishSetSources) + authorize.DELETE("/publish/:prefix/:distribution/sources", apiPublishDropChanges) + authorize.PUT("/publish/:prefix/:distribution/sources/:component", apiPublishUpdateSource) + authorize.DELETE("/publish/:prefix/:distribution/sources/:component", apiPublishRemoveSource) + authorize.POST("/publish/:prefix/:distribution/update", apiPublishUpdate) } { - 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) + 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) } return router diff --git a/api/snapshot.go b/api/snapshot.go index 6082b09a..d4b16c6c 100644 --- a/api/snapshot.go +++ b/api/snapshot.go @@ -251,6 +251,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 5fef46d9..716c8796 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 bc81dc4a..30d29f36 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 a61a5f1f..07765281 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 8e8d2bbd..3d8d19e6 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 42d5d3f2..8c728d43 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 203cc7fe..da4e38a0 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -341,6 +341,7 @@ The legacy json configuration is still supported (and also supports comments): // Storage. First, publishing endpoints should be described in the aptly // configuration file. Each endpoint has its name and associated settings. "AzurePublishEndpoints": { +<<<<<<< HEAD // // Endpoint Name // "test": { @@ -392,12 +393,26 @@ The legacy json configuration is still supported (and also supports comments): // // See: Azure documentation https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string // // defaults to "https://.blob.core.windows.net" // "endpoint": "" - } + }, + + // Authorization for repos may be configured for ldap groups (and is extensible for others), + // default is no authorization. + "Auth": { + // // auth type, only supports ldap currently + // "authType: "", + // // auth server to use (eg. ldaps://ldap.example.com) + // "server\": "", + // // DN for ldap searches + // "ldapDN\": "", + // // ldap filter + // "ldapFilter": "", + // // enable secureTLS, default is off + // "secureTLS": false + } // End of config } - ## 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 da7dfcd6..94f0f11c 100644 --- a/utils/config.go +++ b/utils/config.go @@ -13,6 +13,7 @@ import ( // ConfigStructure is structure of main configuration type ConfigStructure struct { // nolint: maligned +<<<<<<< HEAD // General RootDir string `json:"rootDir" yaml:"root_dir"` LogLevel string `json:"logLevel" yaml:"log_level"` @@ -63,6 +64,10 @@ type ConfigStructure struct { // nolint: maligned SwiftPublishRoots map[string]SwiftPublishRoot `json:"SwiftPublishEndpoints" yaml:"swift_publish_endpoints"` AzurePublishRoots map[string]AzureEndpoint `json:"AzurePublishEndpoints" yaml:"azure_publish_endpoints"` PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage" yaml:"packagepool_storage"` + + // Authentication + UseAuth bool `json:"useAuth"` + Auth AAuth `json:"Auth"` } // DBConfig @@ -211,9 +216,19 @@ type AzureEndpoint struct { Endpoint string `json:"endpoint" yaml:"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", @@ -243,6 +258,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 66f1ad03..19be64c4 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -155,7 +155,15 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"packagePoolStorage\": {\n" + " \"type\": \"local\",\n" + " \"path\": \"/tmp/aptly-pool\"\n" + - " }\n" + + " },\n" + + " \"useAuth\": false,\n"+ + " \"Auth\": {\n"+ + " \"authType\": \"\",\n"+ + " \"server\": \"\",\n"+ + " \"ldapDN\": \"\",\n"+ + " \"ldapFilter\": \"\",\n"+ + " \"secureTLS\": false\n"+ + " }\n"+ "}") }