func authAgent()

in internal/pkg/api/auth.go [90:182]


func authAgent(r *http.Request, id *string, bulker bulk.Bulk, c cache.Cache) (*model.Agent, error) {
	span, ctx := apm.StartSpan(r.Context(), "authAgent", "auth")
	defer span.End()
	r = r.WithContext(ctx)
	start := time.Now()

	// authenticate
	key, err := authAPIKey(r, bulker, c)
	if err != nil {
		return nil, err
	}

	w := hlog.FromRequest(r).With().
		Str(LogAccessAPIKeyID, key.ID)

	if id != nil {
		w = w.Str(LogAgentID, *id)
	}

	zlog := w.Logger()

	authTime := time.Now()

	if authTime.Sub(start) > time.Second {
		zlog.Debug().
			Int64(ECSEventDuration, authTime.Sub(start).Nanoseconds()).
			Msg("authApiKey slow")
	}

	var agent *model.Agent
	// If we have the agentID retrieve the agent document with a get (more performant) instead of triggering a search
	if id != nil {
		agent, err = getAgentAndVerifyAPIKeyID(ctx, bulker, *id, key.ID)
	} else {
		agent, err = findAgentByAPIKeyID(ctx, bulker, key.ID)
	}
	if err != nil {
		return nil, err
	}

	tx := apm.TransactionFromContext(ctx)
	if tx != nil {
		tx.Context.SetLabel("agent_id", agent.Id)
	}

	if agent.Agent == nil {
		zlog.Warn().
			Err(ErrAgentCorrupted).
			Msg("agent record does not contain required metadata section")
		return nil, ErrAgentCorrupted
	}

	findTime := time.Now()

	if findTime.Sub(authTime) > time.Second {
		zlog.Debug().
			Int64(ECSEventDuration, findTime.Sub(authTime).Nanoseconds()).
			Msg("findAgentByApiKeyId slow")
	}

	// validate that the Access ApiKey identifier stored in the agent's record
	// is in alignment when the authenticated key provided on this transaction
	if agent.AccessAPIKeyID != key.ID {
		zlog.Warn().
			Err(ErrAgentCorrupted).
			Str("agent.AccessApiKeyId", agent.AccessAPIKeyID).
			Msg("agent access ApiKey id mismatch agent record")
		return nil, ErrAgentCorrupted
	}

	// validate that the id in the header is equal to the agent id record
	if id != nil && *id != agent.Id {
		zlog.Warn().
			Err(ErrAgentIdentity).
			Str("agent.Id", agent.Id).
			Msg("agent id mismatch against http header")
		return nil, ErrAgentIdentity
	}

	// validate active, an api key can be valid for an inactive agent record
	// if it is in our cache and has not timed out.
	if !agent.Active {
		zlog.Info().
			Err(ErrAgentInactive).
			Msg("agent record inactive")

		// Update the cache to mark the api key id associated with this agent as not enabled
		c.SetAPIKey(*key, false)
		return agent, ErrAgentInactive
	}

	return agent, nil
}