outposts/ldap: optimise backend Search API requests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -99,7 +99,7 @@ func (fe *FlowExecutor) DelegateClientIP(a net.Addr) { | ||||
| func (fe *FlowExecutor) CheckApplicationAccess(appSlug string) (bool, error) { | ||||
| 	acsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.check_access") | ||||
| 	defer acsp.Finish() | ||||
| 	p, _, err := fe.api.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), appSlug).Execute() | ||||
| 	p, _, err := fe.api.CoreApi.CoreApplicationsCheckAccessRetrieve(acsp.Context(), appSlug).Execute() | ||||
| 	if !p.Passing { | ||||
| 		fe.log.Info("Access denied for user") | ||||
| 		return false, nil | ||||
| @ -125,8 +125,9 @@ func (fe *FlowExecutor) Execute() (bool, error) { | ||||
| func (fe *FlowExecutor) solveFlowChallenge(depth int) (bool, error) { | ||||
| 	defer fe.sp.Finish() | ||||
|  | ||||
| 	// Get challenge | ||||
| 	gcsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.get_challenge") | ||||
| 	req := fe.api.FlowsApi.FlowsExecutorGet(context.Background(), fe.flowSlug).Query(fe.Params.Encode()) | ||||
| 	req := fe.api.FlowsApi.FlowsExecutorGet(gcsp.Context(), fe.flowSlug).Query(fe.Params.Encode()) | ||||
| 	challenge, _, err := req.Execute() | ||||
| 	if err != nil { | ||||
| 		return false, errors.New("failed to get challenge") | ||||
| @ -137,7 +138,9 @@ func (fe *FlowExecutor) solveFlowChallenge(depth int) (bool, error) { | ||||
| 	gcsp.SetTag("ak_component", ch.GetComponent()) | ||||
| 	gcsp.Finish() | ||||
|  | ||||
| 	responseReq := fe.api.FlowsApi.FlowsExecutorSolve(context.Background(), fe.flowSlug).Query(fe.Params.Encode()) | ||||
| 	// Resole challenge | ||||
| 	scsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.solve_challenge") | ||||
| 	responseReq := fe.api.FlowsApi.FlowsExecutorSolve(scsp.Context(), fe.flowSlug).Query(fe.Params.Encode()) | ||||
| 	switch ch.GetComponent() { | ||||
| 	case string(StageIdentification): | ||||
| 		responseReq = responseReq.FlowChallengeResponseRequest(api.IdentificationChallengeResponseRequestAsFlowChallengeResponseRequest(api.NewIdentificationChallengeResponseRequest(fe.getAnswer(StageIdentification)))) | ||||
| @ -168,7 +171,6 @@ func (fe *FlowExecutor) solveFlowChallenge(depth int) (bool, error) { | ||||
| 		return false, fmt.Errorf("unsupported challenge type %s", ch.GetComponent()) | ||||
| 	} | ||||
|  | ||||
| 	scsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.solve_challenge") | ||||
| 	response, _, err := responseReq.Execute() | ||||
| 	ch = response.GetActualInstance().(ChallengeInt) | ||||
| 	fe.log.WithField("component", ch.GetComponent()).WithField("type", ch.GetType()).Debug("Got response") | ||||
|  | ||||
| @ -23,7 +23,7 @@ type BindRequest struct { | ||||
| func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { | ||||
| 	span := sentry.StartSpan(context.TODO(), "authentik.providers.ldap.bind", | ||||
| 		sentry.TransactionName("authentik.providers.ldap.bind")) | ||||
| 	span.SetTag("user", bindDN) | ||||
| 	span.SetTag("user.username", bindDN) | ||||
| 	defer span.Finish() | ||||
|  | ||||
| 	bindDN = strings.ToLower(bindDN) | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package ldap | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| @ -34,8 +33,8 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, | ||||
| 	} | ||||
|  | ||||
| 	pi.boundUsersMutex.RLock() | ||||
| 	defer pi.boundUsersMutex.RUnlock() | ||||
| 	flags, ok := pi.boundUsers[req.BindDN] | ||||
| 	pi.boundUsersMutex.RUnlock() | ||||
| 	if !ok { | ||||
| 		pi.log.Debug("User info not cached") | ||||
| 		return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") | ||||
| @ -51,7 +50,7 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, | ||||
| 		return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, req.Filter) | ||||
| 	case GroupObjectClass: | ||||
| 		gapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_group") | ||||
| 		groups, _, err := pi.s.ac.Client.CoreApi.CoreGroupsList(context.Background()).Execute() | ||||
| 		groups, _, err := parseFilterForGroup(pi.s.ac.Client.CoreApi.CoreGroupsList(gapisp.Context()), req.Filter).Execute() | ||||
| 		gapisp.Finish() | ||||
| 		if err != nil { | ||||
| 			return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err) | ||||
| @ -62,7 +61,9 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, | ||||
| 			entries = append(entries, pi.GroupEntry(pi.APIGroupToLDAPGroup(g))) | ||||
| 		} | ||||
|  | ||||
| 		users, _, err := pi.s.ac.Client.CoreApi.CoreUsersList(context.Background()).Execute() | ||||
| 		uapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_user") | ||||
| 		users, _, err := parseFilterForUser(pi.s.ac.Client.CoreApi.CoreUsersList(uapisp.Context()), req.Filter).Execute() | ||||
| 		uapisp.Finish() | ||||
| 		if err != nil { | ||||
| 			return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err) | ||||
| 		} | ||||
| @ -72,7 +73,7 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, | ||||
| 		} | ||||
| 	case UserObjectClass, "": | ||||
| 		uapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_user") | ||||
| 		users, _, err := pi.s.ac.Client.CoreApi.CoreUsersList(context.Background()).Execute() | ||||
| 		users, _, err := parseFilterForUser(pi.s.ac.Client.CoreApi.CoreUsersList(uapisp.Context()), req.Filter).Execute() | ||||
| 		uapisp.Finish() | ||||
|  | ||||
| 		if err != nil { | ||||
|  | ||||
							
								
								
									
										33
									
								
								internal/outpost/ldap/instance_search_group.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								internal/outpost/ldap/instance_search_group.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| package ldap | ||||
|  | ||||
| import ( | ||||
| 	ber "github.com/nmcclain/asn1-ber" | ||||
| 	"github.com/nmcclain/ldap" | ||||
| 	"goauthentik.io/api" | ||||
| ) | ||||
|  | ||||
| func parseFilterForGroup(req api.ApiCoreGroupsListRequest, filter string) api.ApiCoreGroupsListRequest { | ||||
| 	f, err := ldap.CompileFilter(filter) | ||||
| 	if err != nil { | ||||
| 		return req | ||||
| 	} | ||||
| 	switch f.Tag { | ||||
| 	case ldap.FilterEqualityMatch: | ||||
| 		return parseFilterForGroupSingle(req, f) | ||||
| 	case ldap.FilterAnd: | ||||
| 		for _, child := range f.Children { | ||||
| 			req = parseFilterForGroupSingle(req, child) | ||||
| 		} | ||||
| 		return req | ||||
| 	} | ||||
| 	return req | ||||
| } | ||||
|  | ||||
| func parseFilterForGroupSingle(req api.ApiCoreGroupsListRequest, f *ber.Packet) api.ApiCoreGroupsListRequest { | ||||
| 	v := f.Children[1].Value.(string) | ||||
| 	switch f.Children[0].Value.(string) { | ||||
| 	case "cn": | ||||
| 		return req.Name(v) | ||||
| 	} | ||||
| 	return req | ||||
| } | ||||
							
								
								
									
										38
									
								
								internal/outpost/ldap/instance_search_user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								internal/outpost/ldap/instance_search_user.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| package ldap | ||||
|  | ||||
| import ( | ||||
| 	ber "github.com/nmcclain/asn1-ber" | ||||
| 	"github.com/nmcclain/ldap" | ||||
| 	"goauthentik.io/api" | ||||
| ) | ||||
|  | ||||
| func parseFilterForUser(req api.ApiCoreUsersListRequest, filter string) api.ApiCoreUsersListRequest { | ||||
| 	f, err := ldap.CompileFilter(filter) | ||||
| 	if err != nil { | ||||
| 		return req | ||||
| 	} | ||||
| 	switch f.Tag { | ||||
| 	case ldap.FilterEqualityMatch: | ||||
| 		return parseFilterForUserSingle(req, f) | ||||
| 	case ldap.FilterAnd: | ||||
| 		for _, child := range f.Children { | ||||
| 			req = parseFilterForUserSingle(req, child) | ||||
| 		} | ||||
| 		return req | ||||
| 	} | ||||
| 	return req | ||||
| } | ||||
|  | ||||
| func parseFilterForUserSingle(req api.ApiCoreUsersListRequest, f *ber.Packet) api.ApiCoreUsersListRequest { | ||||
| 	v := f.Children[1].Value.(string) | ||||
| 	switch f.Children[0].Value.(string) { | ||||
| 	case "cn": | ||||
| 		return req.Username(v) | ||||
| 	case "name": | ||||
| 	case "displayName": | ||||
| 		return req.Name(v) | ||||
| 	case "mail": | ||||
| 		return req.Email(v) | ||||
| 	} | ||||
| 	return req | ||||
| } | ||||
| @ -24,7 +24,9 @@ type SearchRequest struct { | ||||
|  | ||||
| func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { | ||||
| 	span := sentry.StartSpan(context.TODO(), "authentik.providers.ldap.search", sentry.TransactionName("authentik.providers.ldap.search")) | ||||
| 	span.SetTag("user", bindDN) | ||||
| 	span.SetTag("user.username", bindDN) | ||||
| 	span.SetTag("ak_filter", searchReq.Filter) | ||||
| 	span.SetTag("ak_base_dn", searchReq.BaseDN) | ||||
|  | ||||
| 	defer span.Finish() | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer