outposts/ldap: return user info when user can't search
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -53,8 +53,6 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne | ||||
|  | ||||
| 	// Create new http client that also sets the correct ip | ||||
| 	config := api.NewConfiguration() | ||||
| 	// Carry over the bearer authentication, so that failed login attempts are attributed to the outpost | ||||
| 	config.DefaultHeader = pi.s.ac.Client.GetConfig().DefaultHeader | ||||
| 	config.Host = pi.s.ac.Client.GetConfig().Host | ||||
| 	config.Scheme = pi.s.ac.Client.GetConfig().Scheme | ||||
| 	config.HTTPClient = &http.Client{ | ||||
| @ -76,7 +74,7 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne | ||||
| 	if !passed { | ||||
| 		return ldap.LDAPResultInvalidCredentials, nil | ||||
| 	} | ||||
| 	r, err := pi.s.ac.Client.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), pi.appSlug).Execute() | ||||
| 	r, err := apiClient.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), pi.appSlug).Execute() | ||||
| 	if r.StatusCode == 403 { | ||||
| 		pi.log.WithField("bindDN", bindDN).Info("Access denied for user") | ||||
| 		return ldap.LDAPResultInsufficientAccessRights, nil | ||||
| @ -87,7 +85,7 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne | ||||
| 	} | ||||
| 	pi.log.WithField("bindDN", bindDN).Info("User has access") | ||||
| 	// Get user info to store in context | ||||
| 	userInfo, _, err := pi.s.ac.Client.CoreApi.CoreUsersMeRetrieve(context.Background()).Execute() | ||||
| 	userInfo, _, err := apiClient.CoreApi.CoreUsersMeRetrieve(context.Background()).Execute() | ||||
| 	if err != nil { | ||||
| 		pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info") | ||||
| 		return ldap.LDAPResultOperationsError, nil | ||||
|  | ||||
| @ -8,8 +8,15 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/nmcclain/ldap" | ||||
| 	"goauthentik.io/outpost/api" | ||||
| ) | ||||
|  | ||||
| func (pi *ProviderInstance) SearchMe(user api.User, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { | ||||
| 	entries := make([]*ldap.Entry, 1) | ||||
| 	entries[0] = pi.UserEntry(user) | ||||
| 	return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil | ||||
| } | ||||
|  | ||||
| func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { | ||||
| 	bindDN = strings.ToLower(bindDN) | ||||
| 	baseDN := strings.ToLower("," + pi.BaseDN) | ||||
| @ -29,14 +36,13 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, | ||||
| 	pi.boundUsersMutex.RLock() | ||||
| 	defer pi.boundUsersMutex.RUnlock() | ||||
| 	flags, ok := pi.boundUsers[bindDN] | ||||
| 	pi.log.WithField("bindDN", bindDN).WithField("ok", ok).Debugf("%+v\n", flags) | ||||
| 	if !ok { | ||||
| 		pi.log.Debug("User info not cached") | ||||
| 		return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") | ||||
| 	} | ||||
| 	if !flags.CanSearch { | ||||
| 		pi.log.Debug("User can't search") | ||||
| 		return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") | ||||
| 		pi.log.Debug("User can't search, showing info about user") | ||||
| 		return pi.SearchMe(flags.UserInfo, searchReq, conn) | ||||
| 	} | ||||
|  | ||||
| 	switch filterEntity { | ||||
| @ -49,24 +55,7 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, | ||||
| 		} | ||||
| 		pi.log.WithField("count", len(groups.Results)).Trace("Got results from API") | ||||
| 		for _, g := range groups.Results { | ||||
| 			attrs := []*ldap.EntryAttribute{ | ||||
| 				{ | ||||
| 					Name:   "cn", | ||||
| 					Values: []string{g.Name}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name:   "uid", | ||||
| 					Values: []string{string(g.Pk)}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name:   "objectClass", | ||||
| 					Values: []string{GroupObjectClass, "goauthentik.io/ldap/group"}, | ||||
| 				}, | ||||
| 			} | ||||
| 			attrs = append(attrs, AKAttrsToLDAP(g.Attributes)...) | ||||
|  | ||||
| 			dn := pi.GetGroupDN(g) | ||||
| 			entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs}) | ||||
| 			entries = append(entries, pi.GroupEntry(g)) | ||||
| 		} | ||||
| 	case UserObjectClass, "": | ||||
| 		users, _, err := pi.s.ac.Client.CoreApi.CoreUsersList(context.Background()).Execute() | ||||
| @ -74,6 +63,14 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, | ||||
| 			return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err) | ||||
| 		} | ||||
| 		for _, u := range users.Results { | ||||
| 			entries = append(entries, pi.UserEntry(u)) | ||||
| 		} | ||||
| 	} | ||||
| 	pi.log.WithField("filter", searchReq.Filter).Debug("Search OK") | ||||
| 	return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil | ||||
| } | ||||
|  | ||||
| func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry { | ||||
| 	attrs := []*ldap.EntryAttribute{ | ||||
| 		{ | ||||
| 			Name:   "cn", | ||||
| @ -118,9 +115,27 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, | ||||
| 	attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...) | ||||
|  | ||||
| 	dn := fmt.Sprintf("cn=%s,%s", u.Username, pi.UserDN) | ||||
| 			entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs}) | ||||
|  | ||||
| 	return &ldap.Entry{DN: dn, Attributes: attrs} | ||||
| } | ||||
|  | ||||
| func (pi *ProviderInstance) GroupEntry(g api.Group) *ldap.Entry { | ||||
| 	attrs := []*ldap.EntryAttribute{ | ||||
| 		{ | ||||
| 			Name:   "cn", | ||||
| 			Values: []string{g.Name}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:   "uid", | ||||
| 			Values: []string{string(g.Pk)}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:   "objectClass", | ||||
| 			Values: []string{GroupObjectClass, "goauthentik.io/ldap/group"}, | ||||
| 		}, | ||||
| 	} | ||||
| 	pi.log.WithField("filter", searchReq.Filter).Debug("Search OK") | ||||
| 	return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil | ||||
| 	attrs = append(attrs, AKAttrsToLDAP(g.Attributes)...) | ||||
|  | ||||
| 	dn := pi.GetGroupDN(g) | ||||
| 	return &ldap.Entry{DN: dn, Attributes: attrs} | ||||
| } | ||||
|  | ||||
| @ -9,7 +9,8 @@ import ( | ||||
|  | ||||
| func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute { | ||||
| 	attrList := []*ldap.EntryAttribute{} | ||||
| 	for attrKey, attrValue := range attrs.(map[string]interface{}) { | ||||
| 	a := attrs.(*map[string]interface{}) | ||||
| 	for attrKey, attrValue := range *a { | ||||
| 		entry := &ldap.EntryAttribute{Name: attrKey} | ||||
| 		switch t := attrValue.(type) { | ||||
| 		case []string: | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer