Skip to content

Commit 9e5c5af

Browse files
committed
Adding authorisation options for API access
- ldap currently the only supported method adding authorisation options for local repositories - ldap groups per repo
1 parent f89350e commit 9e5c5af

18 files changed

Lines changed: 630 additions & 180 deletions

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ List of contributors, in chronological order:
4444
* Andre Roth (https://github.com/neolynx)
4545
* Lorenzo Bolla (https://github.com/lbolla)
4646
* Benj Fassbind (https://github.com/randombenj)
47+
* Brett Hawn (https://github.com/bpiraeus)

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ else
55
TAG="$(shell git describe --tags --always)"
66
endif
77
VERSION=$(shell echo $(TAG) | sed 's@^v@@' | sed 's@-@+@g')
8-
PACKAGES=context database deb files gpg http query swift s3 utils
8+
PACKAGES=context database deb files gpg http query swift s3 utils auth
99
PYTHON?=python
1010
TESTS?=
1111
BINPATH?=$(GOPATH)/bin

api/auth.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package api
2+
3+
import (
4+
"crypto/tls"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/gin-contrib/sessions"
9+
"github.com/gin-gonic/gin"
10+
"github.com/go-ldap/ldap/v3"
11+
)
12+
13+
func Authorize(username string, password string) (ok bool) {
14+
config := context.Config()
15+
16+
if config.Auth.Type != "" {
17+
switch strings.ToLower(config.Auth.Type) {
18+
case "ldap":
19+
ok = doLdapAuth(username, password)
20+
default:
21+
return false
22+
}
23+
if ok != true {
24+
return false
25+
}
26+
}
27+
return true
28+
}
29+
30+
func doLdapAuth(username string, password string) bool {
31+
config := context.Config()
32+
attributes := []string{"DN", "CN"}
33+
34+
server := config.Auth.Server
35+
dn := config.Auth.LdapDN
36+
filter := fmt.Sprintf(config.Auth.LdapFilter, username)
37+
38+
// connect to ldap server
39+
conn, err := ldap.Dial("tcp", server)
40+
if err != nil {
41+
return false
42+
}
43+
defer conn.Close()
44+
45+
// reconnect via tls
46+
err = conn.StartTLS(&tls.Config{InsecureSkipVerify: config.Auth.SecureTLS})
47+
if err != nil {
48+
return false
49+
}
50+
51+
// format our request and then fire it off
52+
request := ldap.NewSearchRequest(dn, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, attributes, nil)
53+
search, err := conn.Search(request)
54+
if err != nil {
55+
return false
56+
}
57+
// get our modified dn and then check our user for auth
58+
udn := search.Entries[0].DN
59+
err = conn.Bind(udn, password)
60+
if err != nil {
61+
return false
62+
}
63+
return true
64+
}
65+
66+
func getGroups(c *gin.Context, username string) {
67+
68+
var groups []string
69+
config := context.Config()
70+
dn := fmt.Sprintf("%s", config.Auth.LdapDN)
71+
session := sessions.Default(c)
72+
// connect to ldap server
73+
server := fmt.Sprintf("%s", config.Auth.Server)
74+
conn, err := ldap.Dial("tcp", server)
75+
if err != nil {
76+
return
77+
}
78+
// reconnect via tls
79+
err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true})
80+
if err != nil {
81+
return
82+
}
83+
filter := fmt.Sprintf("(|(member=uid=%s,ou=people,dc=llnw,dc=com)(member=uid=%s,ou=people,dc=llnw,dc=com))", username, username)
84+
request := ldap.NewSearchRequest(dn, ldap.ScopeWholeSubtree, 0, 0, 0, false, filter, []string{"dn", "cn"}, nil)
85+
search, err := conn.Search(request)
86+
if err != nil {
87+
return
88+
}
89+
if len(search.Entries) < 1 {
90+
return
91+
}
92+
for _, v := range search.Entries {
93+
value := strings.Split(strings.TrimLeft(v.DN, "cn="), ",")[0]
94+
groups = append(groups, fmt.Sprintf("%s,", value))
95+
}
96+
session.Set("Groups", groups)
97+
return
98+
}
99+
100+
func checkGroup(c *gin.Context, ldgroup string) bool {
101+
session := sessions.Default(c)
102+
groups := session.Get("Groups")
103+
if ldgroup == "" {
104+
return true
105+
}
106+
for _, v := range groups.([]string) {
107+
if strings.Contains(v, ldgroup) {
108+
return true
109+
}
110+
}
111+
return false
112+
}
113+
114+
func CheckGroup(c *gin.Context, ldgroup string) (err error) {
115+
if !checkGroup(c, ldgroup) {
116+
err = fmt.Errorf("Authorisation Failred")
117+
}
118+
return err
119+
}

api/publish.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
161161
return
162162
}
163163

164+
err = CheckGroup(c, localRepo.LdapGroup)
165+
if err != nil {
166+
c.AbortWithError(403, err)
167+
}
168+
164169
resources = append(resources, string(localRepo.Key()))
165170
err = localCollection.LoadComplete(localRepo)
166171
if err != nil {

api/repos.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func apiReposCreate(c *gin.Context) {
3838
Comment string
3939
DefaultDistribution string
4040
DefaultComponent string
41+
LdapGroup string
4142
}
4243

4344
if c.Bind(&b) != nil {
@@ -47,6 +48,7 @@ func apiReposCreate(c *gin.Context) {
4748
repo := deb.NewLocalRepo(b.Name, b.Comment)
4849
repo.DefaultComponent = b.DefaultComponent
4950
repo.DefaultDistribution = b.DefaultDistribution
51+
repo.LdapGroup = b.LdapGroup
5052

5153
collectionFactory := context.NewCollectionFactory()
5254
collection := collectionFactory.LocalRepoCollection()
@@ -66,6 +68,7 @@ func apiReposEdit(c *gin.Context) {
6668
Comment *string
6769
DefaultDistribution *string
6870
DefaultComponent *string
71+
LdapGroup *string
6972
}
7073

7174
if c.Bind(&b) != nil {
@@ -81,6 +84,12 @@ func apiReposEdit(c *gin.Context) {
8184
return
8285
}
8386

87+
err = CheckGroup(c, repo.LdapGroup)
88+
if err != nil {
89+
c.AbortWithError(403, err)
90+
return
91+
}
92+
8493
if b.Name != nil {
8594
_, err := collection.ByName(*b.Name)
8695
if err == nil {
@@ -99,6 +108,9 @@ func apiReposEdit(c *gin.Context) {
99108
if b.DefaultComponent != nil {
100109
repo.DefaultComponent = *b.DefaultComponent
101110
}
111+
if b.LdapGroup != nil {
112+
repo.LdapGroup = *b.LdapGroup
113+
}
102114

103115
err = collection.Update(repo)
104116
if err != nil {
@@ -139,6 +151,12 @@ func apiReposDrop(c *gin.Context) {
139151
return
140152
}
141153

154+
err = CheckGroup(c, repo.LdapGroup)
155+
if err != nil {
156+
c.AbortWithError(403, err)
157+
return
158+
}
159+
142160
resources := []string{string(repo.Key())}
143161
taskName := fmt.Sprintf("Delete repo %s", name)
144162
maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
@@ -203,6 +221,12 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li
203221
return
204222
}
205223

224+
err = CheckGroup(c, repo.LdapGroup)
225+
if err != nil {
226+
c.AbortWithError(403, err)
227+
return
228+
}
229+
206230
resources := []string{string(repo.Key())}
207231
maybeRunTaskInBackground(c, taskNamePrefix+repo.Name, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
208232
out.Printf("Loading packages...\n")
@@ -294,6 +318,12 @@ func apiReposPackageFromDir(c *gin.Context) {
294318
return
295319
}
296320

321+
err = CheckGroup(c, repo.LdapGroup)
322+
if err != nil {
323+
c.AbortWithError(403, err)
324+
return
325+
}
326+
297327
var taskName string
298328
var sources []string
299329
if fileParam == "" {
@@ -435,6 +465,11 @@ func apiReposIncludePackageFromDir(c *gin.Context) {
435465
c.AbortWithError(404, err)
436466
return
437467
}
468+
err = CheckGroup(c, repo.LdapGroup)
469+
if err != nil {
470+
c.AbortWithError(403, err)
471+
return
472+
}
438473

439474
resources = append(resources, string(repo.Key()))
440475
}

0 commit comments

Comments
 (0)