-
Notifications
You must be signed in to change notification settings - Fork 0
/
ldap.go
132 lines (115 loc) · 3.99 KB
/
ldap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package auth
import (
"crypto/tls"
"errors"
"fmt"
"strconv"
"strings"
"turm/app"
"turm/app/models"
ldap "gopkg.in/ldap.v2"
)
/*LDAPServerAuth implements the authentication of an user against the ldap server after the user
entered his username and password. */
func LDAPServerAuth(credentials *models.Credentials, user *models.User) (success bool, err error) {
//get a TLS encrypted connection
tlsConfig := &tls.Config{InsecureSkipVerify: true}
hostAndPort := fmt.Sprintf("%s:%d", app.LdapHost, app.LdapPort)
l, err := ldap.DialTLS("tcp", hostAndPort, tlsConfig)
if err != nil {
log.Error("error getting the TLS encrypted connection",
"hostAndPort", hostAndPort, "tlsConfig", tlsConfig, "error", err.Error())
return
}
defer l.Close()
/*NOTE: Known ldap 'errors':
- Invalid Credentials: Username and password don't match,
user with these credentials does not exist
- Invalid DN Syntax: The username contains (probably) a comma ',' or
any other bad character
- NDS error: log account expired: The account is no longer active
*/
//try to bind with specified user
base := fmt.Sprintf("cn=%s,ou=user,o=uni", credentials.Username)
err = l.Bind(base, credentials.Password) //actual 'login'
if err != nil {
if !strings.Contains(err.Error(), "Invalid Credentials") &&
!strings.Contains(err.Error(), "Invalid DN Syntax") &&
!strings.Contains(err.Error(), "NDS error: log account expired") {
log.Error("cannot login the user", "base", base, "error", err.Error())
return
}
err = nil
return
}
//at this point the actual login was successful
//now we want to get the user details
//attrNames is used to filter for specific attributes
attrNames := []string{"thuEduStudentNumber", "givenName", "sn", "mail", "thuEduTitle",
"thuEduSalutation", "eduPersonAffiliation", "thuEduAcademicTitle", "thuEduNameExtension"}
//search for the given username
searchRequest := ldap.NewSearchRequest(
base,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
fmt.Sprintf("(&(objectClass=user)(uid=%s))", credentials.Username), //we are looking for a user
attrNames, //attrNames to get only certain ones
nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
log.Error("error getting attributes", "search request", searchRequest, "error", err.Error())
return
}
//must be at least one, because we already logged in with this username
if len(sr.Entries) != 1 {
err = errors.New("user does not exist or too many entries returned")
log.Error(err.Error())
return
}
//get the entry
e := sr.Entries[0]
//now we simly put the data we searched for with attrNames into an user struct
user.FirstName = e.GetAttributeValue("givenName")
user.LastName = e.GetAttributeValue("sn")
user.EMail = strings.ToLower(e.GetAttributeValue("mail"))
user.Affiliations.Affiliations = e.GetAttributeValues("eduPersonAffiliation")
if len(user.Affiliations.Affiliations) != 0 {
user.Affiliations.Valid = true
}
switch salutation := e.GetAttributeValue("thuEduSalutation"); salutation {
case "Frau":
user.Salutation = models.MS
case "Herr":
user.Salutation = models.MR
default:
user.Salutation = models.NONE
}
if e.GetAttributeValue("thuEduTitle") != "" {
user.Title.String = e.GetAttributeValue("thuEduTitle")
user.Title.Valid = true
}
if e.GetAttributeValue("thuEduAcademicTitle") != "" {
user.AcademicTitle.String = e.GetAttributeValue("thuEduAcademicTitle")
user.AcademicTitle.Valid = true
}
if e.GetAttributeValue("thuEduNameExtension") != "" {
user.NameAffix.String = e.GetAttributeValue("thuEduNameExtension")
user.NameAffix.Valid = true
}
//set the matriculation number, if not null
if e.GetAttributeValue("thuEduStudentNumber") != "" {
matrNr, err := strconv.Atoi(e.GetAttributeValue("thuEduStudentNumber"))
if err != nil {
log.Error("error parsing matriculation number",
"matrNr", e.GetAttributeValue("thuEduStudentNumber"), "error", err.Error())
return false, err
}
user.MatrNr.Int32 = int32(matrNr)
user.MatrNr.Valid = true
}
return true, nil
}