Skip to content

Commit 4e48b0b

Browse files
bpiraeusneolynx
authored andcommitted
Adding authorisation options for API access
- ldap currently the only supported method adding authorisation options for local repositories - ldap groups per repo
1 parent ce2966e commit 4e48b0b

14 files changed

Lines changed: 364 additions & 60 deletions

File tree

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ List of contributors, in chronological order:
6363
* Ramón N.Rodriguez (https://github.com/runitonmetal)
6464
* Golf Hu (https://github.com/hudeng-go)
6565
* Cookie Fei (https://github.com/wuhuang26)
66+
* Brett Hawn (https://github.com/bpiraeus)

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
@@ -169,6 +169,11 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
169169
return
170170
}
171171

172+
err = CheckGroup(c, localRepo.LdapGroup)
173+
if err != nil {
174+
c.AbortWithError(403, err)
175+
}
176+
172177
resources = append(resources, string(localRepo.Key()))
173178
err = localCollection.LoadComplete(localRepo)
174179
if err != nil {

api/repos.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func apiReposCreate(c *gin.Context) {
8787
Comment string
8888
DefaultDistribution string
8989
DefaultComponent string
90+
LdapGroup string
9091
}
9192

9293
if c.Bind(&b) != nil {
@@ -96,6 +97,7 @@ func apiReposCreate(c *gin.Context) {
9697
repo := deb.NewLocalRepo(b.Name, b.Comment)
9798
repo.DefaultComponent = b.DefaultComponent
9899
repo.DefaultDistribution = b.DefaultDistribution
100+
repo.LdapGroup = b.LdapGroup
99101

100102
collectionFactory := context.NewCollectionFactory()
101103
collection := collectionFactory.LocalRepoCollection()
@@ -115,6 +117,7 @@ func apiReposEdit(c *gin.Context) {
115117
Comment *string
116118
DefaultDistribution *string
117119
DefaultComponent *string
120+
LdapGroup *string
118121
}
119122

120123
if c.Bind(&b) != nil {
@@ -130,6 +133,12 @@ func apiReposEdit(c *gin.Context) {
130133
return
131134
}
132135

136+
err = CheckGroup(c, repo.LdapGroup)
137+
if err != nil {
138+
c.AbortWithError(403, err)
139+
return
140+
}
141+
133142
if b.Name != nil {
134143
_, err := collection.ByName(*b.Name)
135144
if err == nil {
@@ -148,6 +157,9 @@ func apiReposEdit(c *gin.Context) {
148157
if b.DefaultComponent != nil {
149158
repo.DefaultComponent = *b.DefaultComponent
150159
}
160+
if b.LdapGroup != nil {
161+
repo.LdapGroup = *b.LdapGroup
162+
}
151163

152164
err = collection.Update(repo)
153165
if err != nil {
@@ -196,6 +208,12 @@ func apiReposDrop(c *gin.Context) {
196208
return
197209
}
198210

211+
err = CheckGroup(c, repo.LdapGroup)
212+
if err != nil {
213+
c.AbortWithError(403, err)
214+
return
215+
}
216+
199217
resources := []string{string(repo.Key())}
200218
taskName := fmt.Sprintf("Delete repo %s", name)
201219
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
260278
return
261279
}
262280

281+
err = CheckGroup(c, repo.LdapGroup)
282+
if err != nil {
283+
c.AbortWithError(403, err)
284+
return
285+
}
286+
263287
resources := []string{string(repo.Key())}
264288
maybeRunTaskInBackground(c, taskNamePrefix+repo.Name, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) {
265289
out.Printf("Loading packages...\n")
@@ -366,6 +390,12 @@ func apiReposPackageFromDir(c *gin.Context) {
366390
return
367391
}
368392

393+
err = CheckGroup(c, repo.LdapGroup)
394+
if err != nil {
395+
c.AbortWithError(403, err)
396+
return
397+
}
398+
369399
var taskName string
370400
var sources []string
371401
if fileParam == "" {
@@ -651,6 +681,11 @@ func apiReposIncludePackageFromDir(c *gin.Context) {
651681
AbortWithJSONError(c, 404, err)
652682
return
653683
}
684+
err = CheckGroup(c, repo.LdapGroup)
685+
if err != nil {
686+
c.AbortWithError(403, err)
687+
return
688+
}
654689

655690
resources = append(resources, string(repo.Key()))
656691
}

0 commit comments

Comments
 (0)