mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 04:29:04 +08:00
fix: refactor auth package (#7110)
* fix: refactor auth package * fix: minor changes * fix: refactor jwt * fix: add tests and address comments * fix: address comments * fix: add uncomitted file * fix: address comments * fix: update tests
This commit is contained in:
parent
fbf0e4efc7
commit
c3951afdfd
36
ee/http/middleware/pat.go
Normal file
36
ee/http/middleware/pat.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pat struct {
|
||||||
|
uuid *authtypes.UUID
|
||||||
|
headers []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPat(headers []string) *Pat {
|
||||||
|
return &Pat{uuid: authtypes.NewUUID(), headers: headers}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pat) Wrap(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var values []string
|
||||||
|
for _, header := range p.headers {
|
||||||
|
values = append(values, r.Header.Get(header))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err := p.uuid.ContextFromRequest(r.Context(), values...)
|
||||||
|
if err != nil {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
@ -20,6 +20,7 @@ import (
|
|||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
rules "go.signoz.io/signoz/pkg/query-service/rules"
|
rules "go.signoz.io/signoz/pkg/query-service/rules"
|
||||||
"go.signoz.io/signoz/pkg/query-service/version"
|
"go.signoz.io/signoz/pkg/query-service/version"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIHandlerOptions struct {
|
type APIHandlerOptions struct {
|
||||||
@ -41,6 +42,7 @@ type APIHandlerOptions struct {
|
|||||||
FluxInterval time.Duration
|
FluxInterval time.Duration
|
||||||
UseLogsNewSchema bool
|
UseLogsNewSchema bool
|
||||||
UseTraceNewSchema bool
|
UseTraceNewSchema bool
|
||||||
|
JWT *authtypes.JWT
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIHandler struct {
|
type APIHandler struct {
|
||||||
|
@ -50,7 +50,7 @@ func (ah *APIHandler) loginUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if all looks good, call auth
|
// if all looks good, call auth
|
||||||
resp, err := baseauth.Login(ctx, &req)
|
resp, err := baseauth.Login(ctx, &req, ah.opts.JWT)
|
||||||
if ah.HandleError(w, err, http.StatusUnauthorized) {
|
if ah.HandleError(w, err, http.StatusUnauthorized) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ func (ah *APIHandler) receiveGoogleAuth(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, identity.Email)
|
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, identity.Email, ah.opts.JWT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("[receiveGoogleAuth] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err))
|
zap.L().Error("[receiveGoogleAuth] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err))
|
||||||
handleSsoError(w, r, redirectUri)
|
handleSsoError(w, r, redirectUri)
|
||||||
@ -331,7 +331,7 @@ func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, email)
|
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, email, ah.opts.JWT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("[receiveSAML] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err))
|
zap.L().Error("[receiveSAML] failed to generate redirect URI after successful login ", zap.String("domain", domain.String()), zap.Error(err))
|
||||||
handleSsoError(w, r, redirectUri)
|
handleSsoError(w, r, redirectUri)
|
||||||
|
@ -37,7 +37,7 @@ func (ah *APIHandler) CloudIntegrationsGenerateConnectionParams(w http.ResponseW
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
currentUser, err := auth.GetUserFromRequest(r)
|
currentUser, err := auth.GetUserFromReqContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, basemodel.UnauthorizedError(fmt.Errorf(
|
RespondError(w, basemodel.UnauthorizedError(fmt.Errorf(
|
||||||
"couldn't deduce current user: %w", err,
|
"couldn't deduce current user: %w", err,
|
||||||
|
@ -34,7 +34,7 @@ func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) {
|
|||||||
RespondError(w, model.BadRequest(err), nil)
|
RespondError(w, model.BadRequest(err), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, err := auth.GetUserFromRequest(r)
|
user, err := auth.GetUserFromReqContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -97,7 +97,7 @@ func (ah *APIHandler) updatePAT(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := auth.GetUserFromRequest(r)
|
user, err := auth.GetUserFromReqContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -127,7 +127,7 @@ func (ah *APIHandler) updatePAT(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
|
func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
user, err := auth.GetUserFromRequest(r)
|
user, err := auth.GetUserFromReqContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -147,7 +147,7 @@ func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (ah *APIHandler) revokePAT(w http.ResponseWriter, r *http.Request) {
|
func (ah *APIHandler) revokePAT(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(r)["id"]
|
||||||
user, err := auth.GetUserFromRequest(r)
|
user, err := auth.GetUserFromReqContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
"github.com/soheilhy/cmux"
|
"github.com/soheilhy/cmux"
|
||||||
|
eemiddleware "go.signoz.io/signoz/ee/http/middleware"
|
||||||
"go.signoz.io/signoz/ee/query-service/app/api"
|
"go.signoz.io/signoz/ee/query-service/app/api"
|
||||||
"go.signoz.io/signoz/ee/query-service/app/db"
|
"go.signoz.io/signoz/ee/query-service/app/db"
|
||||||
"go.signoz.io/signoz/ee/query-service/auth"
|
"go.signoz.io/signoz/ee/query-service/auth"
|
||||||
@ -24,6 +25,7 @@ import (
|
|||||||
"go.signoz.io/signoz/ee/query-service/rules"
|
"go.signoz.io/signoz/ee/query-service/rules"
|
||||||
"go.signoz.io/signoz/pkg/http/middleware"
|
"go.signoz.io/signoz/pkg/http/middleware"
|
||||||
"go.signoz.io/signoz/pkg/signoz"
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.signoz.io/signoz/pkg/web"
|
"go.signoz.io/signoz/pkg/web"
|
||||||
|
|
||||||
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
licensepkg "go.signoz.io/signoz/ee/query-service/license"
|
||||||
@ -72,6 +74,7 @@ type ServerOptions struct {
|
|||||||
GatewayUrl string
|
GatewayUrl string
|
||||||
UseLogsNewSchema bool
|
UseLogsNewSchema bool
|
||||||
UseTraceNewSchema bool
|
UseTraceNewSchema bool
|
||||||
|
Jwt *authtypes.JWT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server runs HTTP api service
|
// Server runs HTTP api service
|
||||||
@ -261,6 +264,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
GatewayUrl: serverOptions.GatewayUrl,
|
GatewayUrl: serverOptions.GatewayUrl,
|
||||||
UseLogsNewSchema: serverOptions.UseLogsNewSchema,
|
UseLogsNewSchema: serverOptions.UseLogsNewSchema,
|
||||||
UseTraceNewSchema: serverOptions.UseTraceNewSchema,
|
UseTraceNewSchema: serverOptions.UseTraceNewSchema,
|
||||||
|
JWT: serverOptions.Jwt,
|
||||||
}
|
}
|
||||||
|
|
||||||
apiHandler, err := api.NewAPIHandler(apiOpts)
|
apiHandler, err := api.NewAPIHandler(apiOpts)
|
||||||
@ -303,6 +307,8 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server,
|
|||||||
|
|
||||||
r := baseapp.NewRouter()
|
r := baseapp.NewRouter()
|
||||||
|
|
||||||
|
r.Use(middleware.NewAuth(zap.L(), s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
|
r.Use(eemiddleware.NewPat([]string{"SIGNOZ-API-KEY"}).Wrap)
|
||||||
r.Use(middleware.NewTimeout(zap.L(),
|
r.Use(middleware.NewTimeout(zap.L(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
@ -334,8 +340,8 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
|
|||||||
r := baseapp.NewRouter()
|
r := baseapp.NewRouter()
|
||||||
|
|
||||||
// add auth middleware
|
// add auth middleware
|
||||||
getUserFromRequest := func(r *http.Request) (*basemodel.UserPayload, error) {
|
getUserFromRequest := func(ctx context.Context) (*basemodel.UserPayload, error) {
|
||||||
user, err := auth.GetUserFromRequest(r, apiHandler)
|
user, err := auth.GetUserFromRequestContext(ctx, apiHandler)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -349,6 +355,8 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
|
|||||||
}
|
}
|
||||||
am := baseapp.NewAuthMiddleware(getUserFromRequest)
|
am := baseapp.NewAuthMiddleware(getUserFromRequest)
|
||||||
|
|
||||||
|
r.Use(middleware.NewAuth(zap.L(), s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
|
r.Use(eemiddleware.NewPat([]string{"SIGNOZ-API-KEY"}).Wrap)
|
||||||
r.Use(middleware.NewTimeout(zap.L(),
|
r.Use(middleware.NewTimeout(zap.L(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
|
@ -3,20 +3,20 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.signoz.io/signoz/ee/query-service/app/api"
|
"go.signoz.io/signoz/ee/query-service/app/api"
|
||||||
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetUserFromRequest(r *http.Request, apiHandler *api.APIHandler) (*basemodel.UserPayload, error) {
|
func GetUserFromRequestContext(ctx context.Context, apiHandler *api.APIHandler) (*basemodel.UserPayload, error) {
|
||||||
patToken := r.Header.Get("SIGNOZ-API-KEY")
|
patToken, ok := authtypes.UUIDFromContext(ctx)
|
||||||
if len(patToken) > 0 {
|
if ok && patToken != "" {
|
||||||
zap.L().Debug("Received a non-zero length PAT token")
|
zap.L().Debug("Received a non-zero length PAT token")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
dao := apiHandler.AppDao()
|
dao := apiHandler.AppDao()
|
||||||
@ -52,5 +52,5 @@ func GetUserFromRequest(r *http.Request, apiHandler *api.APIHandler) (*basemodel
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return baseauth.GetUserFromRequest(r)
|
return baseauth.GetUserFromReqContext(ctx)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
basedao "go.signoz.io/signoz/pkg/query-service/dao"
|
basedao "go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
|
baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ModelDao interface {
|
type ModelDao interface {
|
||||||
@ -22,7 +23,7 @@ type ModelDao interface {
|
|||||||
|
|
||||||
// auth methods
|
// auth methods
|
||||||
CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError)
|
CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError)
|
||||||
PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError)
|
PrepareSsoRedirect(ctx context.Context, redirectUri, email string, jwt *authtypes.JWT) (redirectURL string, apierr basemodel.BaseApiError)
|
||||||
GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error)
|
GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error)
|
||||||
|
|
||||||
// org domain (auth domains) CRUD ops
|
// org domain (auth domains) CRUD ops
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ func (m *modelDao) createUserForSAMLRequest(ctx context.Context, email string) (
|
|||||||
|
|
||||||
// PrepareSsoRedirect prepares redirect page link after SSO response
|
// PrepareSsoRedirect prepares redirect page link after SSO response
|
||||||
// is successfully parsed (i.e. valid email is available)
|
// is successfully parsed (i.e. valid email is available)
|
||||||
func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError) {
|
func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email string, jwt *authtypes.JWT) (redirectURL string, apierr basemodel.BaseApiError) {
|
||||||
|
|
||||||
userPayload, apierr := m.GetUserByEmail(ctx, email)
|
userPayload, apierr := m.GetUserByEmail(ctx, email)
|
||||||
if !apierr.IsNil() {
|
if !apierr.IsNil() {
|
||||||
@ -85,7 +86,7 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
|
|||||||
user = &userPayload.User
|
user = &userPayload.User
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenStore, err := baseauth.GenerateJWTForUser(user)
|
tokenStore, err := baseauth.GenerateJWTForUser(user, jwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("failed to generate token for SSO login user", zap.Error(err))
|
zap.L().Error("failed to generate token for SSO login user", zap.Error(err))
|
||||||
return "", model.InternalErrorStr("failed to generate token for the user")
|
return "", model.InternalErrorStr("failed to generate token for the user")
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
baseconstants "go.signoz.io/signoz/pkg/query-service/constants"
|
baseconstants "go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
validate "go.signoz.io/signoz/ee/query-service/integrations/signozio"
|
validate "go.signoz.io/signoz/ee/query-service/integrations/signozio"
|
||||||
"go.signoz.io/signoz/ee/query-service/model"
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
@ -237,10 +237,10 @@ func (lm *Manager) ValidateV3(ctx context.Context) (reterr error) {
|
|||||||
func (lm *Manager) ActivateV3(ctx context.Context, licenseKey string) (licenseResponse *model.LicenseV3, errResponse *model.ApiError) {
|
func (lm *Manager) ActivateV3(ctx context.Context, licenseKey string) (licenseResponse *model.LicenseV3, errResponse *model.ApiError) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if errResponse != nil {
|
if errResponse != nil {
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED,
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_LICENSE_ACT_FAILED,
|
||||||
map[string]interface{}{"err": errResponse.Err.Error()}, userEmail, true, false)
|
map[string]interface{}{"err": errResponse.Err.Error()}, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/version"
|
"go.signoz.io/signoz/pkg/query-service/version"
|
||||||
"go.signoz.io/signoz/pkg/signoz"
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
|
||||||
@ -154,6 +155,16 @@ func main() {
|
|||||||
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jwtSecret := os.Getenv("SIGNOZ_JWT_SECRET")
|
||||||
|
|
||||||
|
if len(jwtSecret) == 0 {
|
||||||
|
zap.L().Warn("No JWT secret key is specified.")
|
||||||
|
} else {
|
||||||
|
zap.L().Info("JWT secret key set successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt := authtypes.NewJWT(jwtSecret, 30*time.Minute, 30*24*time.Hour)
|
||||||
|
|
||||||
serverOptions := &app.ServerOptions{
|
serverOptions := &app.ServerOptions{
|
||||||
Config: config,
|
Config: config,
|
||||||
SigNoz: signoz,
|
SigNoz: signoz,
|
||||||
@ -171,15 +182,7 @@ func main() {
|
|||||||
GatewayUrl: gatewayUrl,
|
GatewayUrl: gatewayUrl,
|
||||||
UseLogsNewSchema: useLogsNewSchema,
|
UseLogsNewSchema: useLogsNewSchema,
|
||||||
UseTraceNewSchema: useTraceNewSchema,
|
UseTraceNewSchema: useTraceNewSchema,
|
||||||
}
|
Jwt: jwt,
|
||||||
|
|
||||||
// Read the jwt secret key
|
|
||||||
auth.JwtSecret = os.Getenv("SIGNOZ_JWT_SECRET")
|
|
||||||
|
|
||||||
if len(auth.JwtSecret) == 0 {
|
|
||||||
zap.L().Warn("No JWT secret key is specified.")
|
|
||||||
} else {
|
|
||||||
zap.L().Info("JWT secret key set successfully.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := app.NewServer(serverOptions)
|
server, err := app.NewServer(serverOptions)
|
||||||
|
5
go.mod
5
go.mod
@ -13,7 +13,6 @@ require (
|
|||||||
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974
|
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974
|
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974
|
||||||
github.com/antonmedv/expr v1.15.3
|
github.com/antonmedv/expr v1.15.3
|
||||||
github.com/auth0/go-jwt-middleware v1.0.1
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0
|
github.com/cespare/xxhash/v2 v2.3.0
|
||||||
github.com/coreos/go-oidc/v3 v3.11.0
|
github.com/coreos/go-oidc/v3 v3.11.0
|
||||||
github.com/dustin/go-humanize v1.0.1
|
github.com/dustin/go-humanize v1.0.1
|
||||||
@ -24,7 +23,7 @@ require (
|
|||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/go-redis/redismock/v8 v8.11.5
|
github.com/go-redis/redismock/v8 v8.11.5
|
||||||
github.com/go-viper/mapstructure/v2 v2.1.0
|
github.com/go-viper/mapstructure/v2 v2.1.0
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
@ -112,7 +111,6 @@ require (
|
|||||||
github.com/expr-lang/expr v1.16.9 // indirect
|
github.com/expr-lang/expr v1.16.9 // indirect
|
||||||
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
|
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/go-faster/city v1.0.1 // indirect
|
github.com/go-faster/city v1.0.1 // indirect
|
||||||
github.com/go-faster/errors v0.7.1 // indirect
|
github.com/go-faster/errors v0.7.1 // indirect
|
||||||
@ -132,7 +130,6 @@ require (
|
|||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||||
|
16
go.sum
16
go.sum
@ -124,8 +124,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
|||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/auth0/go-jwt-middleware v1.0.1 h1:/fsQ4vRr4zod1wKReUH+0A3ySRjGiT9G34kypO/EKwI=
|
|
||||||
github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM=
|
|
||||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
||||||
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||||
@ -246,9 +244,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
|
|||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
@ -337,8 +332,6 @@ github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
|
|||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@ -444,13 +437,10 @@ github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK
|
|||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/gophercloud/gophercloud v1.14.0 h1:Bt9zQDhPrbd4qX7EILGmy+i7GP35cc+AAL2+wIJpUE8=
|
github.com/gophercloud/gophercloud v1.14.0 h1:Bt9zQDhPrbd4qX7EILGmy+i7GP35cc+AAL2+wIJpUE8=
|
||||||
github.com/gophercloud/gophercloud v1.14.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
github.com/gophercloud/gophercloud v1.14.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
@ -864,9 +854,6 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
|
||||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||||
@ -920,8 +907,6 @@ github.com/uptrace/bun/dialect/pgdialect v1.2.9 h1:caf5uFbOGiXvadV6pA5gn87k0awFF
|
|||||||
github.com/uptrace/bun/dialect/pgdialect v1.2.9/go.mod h1:m7L9JtOp/Lt8HccET70ULxplMweE/u0S9lNUSxz2duo=
|
github.com/uptrace/bun/dialect/pgdialect v1.2.9/go.mod h1:m7L9JtOp/Lt8HccET70ULxplMweE/u0S9lNUSxz2duo=
|
||||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9 h1:HLzGWXBh07sT8zhVPy6veYbbGrAtYq0KzyRHXBj+GjA=
|
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9 h1:HLzGWXBh07sT8zhVPy6veYbbGrAtYq0KzyRHXBj+GjA=
|
||||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9/go.mod h1:dUR+ecoCWA0FIa9vhQVRnGtYYPpuCLJoEEtX9E1aiBU=
|
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9/go.mod h1:dUR+ecoCWA0FIa9vhQVRnGtYYPpuCLJoEEtX9E1aiBU=
|
||||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=
|
github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=
|
||||||
@ -1366,7 +1351,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
|||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
@ -7,12 +7,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
// TODO(remove): Remove auth packages
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,8 +28,6 @@ func NewAnalytics(logger *zap.Logger) *Analytics {
|
|||||||
|
|
||||||
func (a *Analytics) Wrap(next http.Handler) http.Handler {
|
func (a *Analytics) Wrap(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := auth.AttachJwtToContext(r.Context(), r)
|
|
||||||
r = r.WithContext(ctx)
|
|
||||||
route := mux.CurrentRoute(r)
|
route := mux.CurrentRoute(r)
|
||||||
path, _ := route.GetPathTemplate()
|
path, _ := route.GetPathTemplate()
|
||||||
|
|
||||||
@ -50,9 +46,9 @@ func (a *Analytics) Wrap(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := telemetry.EnabledPaths()[path]; ok {
|
if _, ok := telemetry.EnabledPaths()[path]; ok {
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +134,8 @@ func (a *Analytics) extractQueryRangeData(path string, r *http.Request) (map[str
|
|||||||
data["queryType"] = queryInfoResult.QueryType
|
data["queryType"] = queryInfoResult.QueryType
|
||||||
data["panelType"] = queryInfoResult.PanelType
|
data["panelType"] = queryInfoResult.PanelType
|
||||||
|
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
// switch case to set data["screen"] based on the referrer
|
// switch case to set data["screen"] based on the referrer
|
||||||
switch {
|
switch {
|
||||||
case dashboardMatched:
|
case dashboardMatched:
|
||||||
@ -154,7 +150,7 @@ func (a *Analytics) extractQueryRangeData(path string, r *http.Request) (map[str
|
|||||||
data["screen"] = "unknown"
|
data["screen"] = "unknown"
|
||||||
return data, true
|
return data, true
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_QUERY_RANGE_API, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data, true
|
return data, true
|
||||||
|
44
pkg/http/middleware/auth.go
Normal file
44
pkg/http/middleware/auth.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
jwt *authtypes.JWT
|
||||||
|
headers []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuth(logger *zap.Logger, jwt *authtypes.JWT, headers []string) *Auth {
|
||||||
|
if logger == nil {
|
||||||
|
panic("cannot build auth middleware, logger is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Auth{logger: logger, jwt: jwt, headers: headers}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) Wrap(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var values []string
|
||||||
|
for _, header := range a.headers {
|
||||||
|
values = append(values, r.Header.Get(header))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err := a.jwt.ContextFromRequest(
|
||||||
|
r.Context(),
|
||||||
|
values...)
|
||||||
|
if err != nil {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -133,7 +133,11 @@ func (middleware *Logging) getLogCommentKVs(r *http.Request) map[string]string {
|
|||||||
client = "api"
|
client = "api"
|
||||||
}
|
}
|
||||||
|
|
||||||
email, _ := auth.GetEmailFromJwt(r.Context())
|
var email string
|
||||||
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
if ok {
|
||||||
|
email = claims.Email
|
||||||
|
}
|
||||||
|
|
||||||
kvs := map[string]string{
|
kvs := map[string]string{
|
||||||
"path": path,
|
"path": path,
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AuthMiddleware struct {
|
type AuthMiddleware struct {
|
||||||
GetUserFromRequest func(r *http.Request) (*model.UserPayload, error)
|
GetUserFromRequest func(r context.Context) (*model.UserPayload, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthMiddleware(f func(r *http.Request) (*model.UserPayload, error)) *AuthMiddleware {
|
func NewAuthMiddleware(f func(ctx context.Context) (*model.UserPayload, error)) *AuthMiddleware {
|
||||||
return &AuthMiddleware{
|
return &AuthMiddleware{
|
||||||
GetUserFromRequest: f,
|
GetUserFromRequest: f,
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ func (am *AuthMiddleware) OpenAccess(f func(http.ResponseWriter, *http.Request))
|
|||||||
|
|
||||||
func (am *AuthMiddleware) ViewAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
func (am *AuthMiddleware) ViewAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
user, err := am.GetUserFromRequest(r)
|
user, err := am.GetUserFromRequest(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -53,7 +53,7 @@ func (am *AuthMiddleware) ViewAccess(f func(http.ResponseWriter, *http.Request))
|
|||||||
|
|
||||||
func (am *AuthMiddleware) EditAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
func (am *AuthMiddleware) EditAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
user, err := am.GetUserFromRequest(r)
|
user, err := am.GetUserFromRequest(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -76,7 +76,7 @@ func (am *AuthMiddleware) EditAccess(f func(http.ResponseWriter, *http.Request))
|
|||||||
|
|
||||||
func (am *AuthMiddleware) SelfAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
func (am *AuthMiddleware) SelfAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
user, err := am.GetUserFromRequest(r)
|
user, err := am.GetUserFromRequest(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
@ -100,7 +100,7 @@ func (am *AuthMiddleware) SelfAccess(f func(http.ResponseWriter, *http.Request))
|
|||||||
|
|
||||||
func (am *AuthMiddleware) AdminAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
func (am *AuthMiddleware) AdminAccess(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
user, err := am.GetUserFromRequest(r)
|
user, err := am.GetUserFromRequest(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{
|
RespondError(w, &model.ApiError{
|
||||||
Typ: model.ErrorUnauthorized,
|
Typ: model.ErrorUnauthorized,
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.signoz.io/signoz/pkg/cache"
|
"go.signoz.io/signoz/pkg/cache"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
promModel "github.com/prometheus/common/model"
|
promModel "github.com/prometheus/common/model"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -43,7 +44,6 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/resource"
|
"go.signoz.io/signoz/pkg/query-service/app/resource"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/services"
|
"go.signoz.io/signoz/pkg/query-service/app/services"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/traces/tracedetail"
|
"go.signoz.io/signoz/pkg/query-service/app/traces/tracedetail"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
chErrors "go.signoz.io/signoz/pkg/query-service/errors"
|
chErrors "go.signoz.io/signoz/pkg/query-service/errors"
|
||||||
@ -1164,23 +1164,23 @@ func (r *ClickHouseReader) SearchTracesV2(ctx context.Context, params *model.Sea
|
|||||||
if traceSummary.NumSpans > uint64(params.MaxSpansInTrace) {
|
if traceSummary.NumSpans > uint64(params.MaxSpansInTrace) {
|
||||||
zap.L().Error("Max spans allowed in a trace limit reached", zap.Int("MaxSpansInTrace", params.MaxSpansInTrace),
|
zap.L().Error("Max spans allowed in a trace limit reached", zap.Int("MaxSpansInTrace", params.MaxSpansInTrace),
|
||||||
zap.Uint64("Count", traceSummary.NumSpans))
|
zap.Uint64("Count", traceSummary.NumSpans))
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": traceSummary.NumSpans,
|
"traceSize": traceSummary.NumSpans,
|
||||||
"maxSpansInTraceLimit": params.MaxSpansInTrace,
|
"maxSpansInTraceLimit": params.MaxSpansInTrace,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("max spans allowed in trace limit reached, please contact support for more details")
|
return nil, fmt.Errorf("max spans allowed in trace limit reached, please contact support for more details")
|
||||||
}
|
}
|
||||||
|
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": traceSummary.NumSpans,
|
"traceSize": traceSummary.NumSpans,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var startTime, endTime, durationNano uint64
|
var startTime, endTime, durationNano uint64
|
||||||
@ -1266,13 +1266,13 @@ func (r *ClickHouseReader) SearchTracesV2(ctx context.Context, params *model.Sea
|
|||||||
}
|
}
|
||||||
end = time.Now()
|
end = time.Now()
|
||||||
zap.L().Debug("smartTraceAlgo took: ", zap.Duration("duration", end.Sub(start)))
|
zap.L().Debug("smartTraceAlgo took: ", zap.Duration("duration", end.Sub(start)))
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": len(searchScanResponses),
|
"traceSize": len(searchScanResponses),
|
||||||
"spansRenderLimit": params.SpansRenderLimit,
|
"spansRenderLimit": params.SpansRenderLimit,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LARGE_TRACE_OPENED, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LARGE_TRACE_OPENED, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i, item := range searchSpanResponses {
|
for i, item := range searchSpanResponses {
|
||||||
@ -1306,23 +1306,23 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, params *model.Searc
|
|||||||
if countSpans > uint64(params.MaxSpansInTrace) {
|
if countSpans > uint64(params.MaxSpansInTrace) {
|
||||||
zap.L().Error("Max spans allowed in a trace limit reached", zap.Int("MaxSpansInTrace", params.MaxSpansInTrace),
|
zap.L().Error("Max spans allowed in a trace limit reached", zap.Int("MaxSpansInTrace", params.MaxSpansInTrace),
|
||||||
zap.Uint64("Count", countSpans))
|
zap.Uint64("Count", countSpans))
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": countSpans,
|
"traceSize": countSpans,
|
||||||
"maxSpansInTraceLimit": params.MaxSpansInTrace,
|
"maxSpansInTraceLimit": params.MaxSpansInTrace,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("max spans allowed in trace limit reached, please contact support for more details")
|
return nil, fmt.Errorf("max spans allowed in trace limit reached, please contact support for more details")
|
||||||
}
|
}
|
||||||
|
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": countSpans,
|
"traceSize": countSpans,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var startTime, endTime, durationNano uint64
|
var startTime, endTime, durationNano uint64
|
||||||
@ -1379,13 +1379,13 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, params *model.Searc
|
|||||||
}
|
}
|
||||||
end = time.Now()
|
end = time.Now()
|
||||||
zap.L().Debug("smartTraceAlgo took: ", zap.Duration("duration", end.Sub(start)))
|
zap.L().Debug("smartTraceAlgo took: ", zap.Duration("duration", end.Sub(start)))
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"traceSize": len(searchScanResponses),
|
"traceSize": len(searchScanResponses),
|
||||||
"spansRenderLimit": params.SpansRenderLimit,
|
"spansRenderLimit": params.SpansRenderLimit,
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LARGE_TRACE_OPENED, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LARGE_TRACE_OPENED, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i, item := range searchSpanResponses {
|
for i, item := range searchSpanResponses {
|
||||||
@ -1455,7 +1455,7 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
|
|||||||
var serviceNameIntervalMap = map[string][]tracedetail.Interval{}
|
var serviceNameIntervalMap = map[string][]tracedetail.Interval{}
|
||||||
var hasMissingSpans bool
|
var hasMissingSpans bool
|
||||||
|
|
||||||
userEmail , emailErr := auth.GetEmailFromJwt(ctx)
|
claims, claimsPresent := authtypes.ClaimsFromContext(ctx)
|
||||||
cachedTraceData, err := r.GetWaterfallSpansForTraceWithMetadataCache(ctx, traceID)
|
cachedTraceData, err := r.GetWaterfallSpansForTraceWithMetadataCache(ctx, traceID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
startTime = cachedTraceData.StartTime
|
startTime = cachedTraceData.StartTime
|
||||||
@ -1468,8 +1468,8 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
|
|||||||
totalErrorSpans = cachedTraceData.TotalErrorSpans
|
totalErrorSpans = cachedTraceData.TotalErrorSpans
|
||||||
hasMissingSpans = cachedTraceData.HasMissingSpans
|
hasMissingSpans = cachedTraceData.HasMissingSpans
|
||||||
|
|
||||||
if emailErr == nil {
|
if claimsPresent {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,8 +1485,8 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
|
|||||||
}
|
}
|
||||||
totalSpans = uint64(len(searchScanResponses))
|
totalSpans = uint64(len(searchScanResponses))
|
||||||
|
|
||||||
if emailErr == nil {
|
if claimsPresent {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, map[string]interface{}{"traceSize": totalSpans}, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
processingBeforeCache := time.Now()
|
processingBeforeCache := time.Now()
|
||||||
@ -1531,8 +1531,8 @@ func (r *ClickHouseReader) GetWaterfallSpansForTraceWithMetadata(ctx context.Con
|
|||||||
if startTime == 0 || startTimeUnixNano < startTime {
|
if startTime == 0 || startTimeUnixNano < startTime {
|
||||||
startTime = startTimeUnixNano
|
startTime = startTimeUnixNano
|
||||||
}
|
}
|
||||||
if endTime == 0 || (startTimeUnixNano + jsonItem.DurationNano ) > endTime {
|
if endTime == 0 || (startTimeUnixNano+jsonItem.DurationNano) > endTime {
|
||||||
endTime = (startTimeUnixNano + jsonItem.DurationNano )
|
endTime = (startTimeUnixNano + jsonItem.DurationNano)
|
||||||
}
|
}
|
||||||
if durationNano == 0 || jsonItem.DurationNano > durationNano {
|
if durationNano == 0 || jsonItem.DurationNano > durationNano {
|
||||||
durationNano = jsonItem.DurationNano
|
durationNano = jsonItem.DurationNano
|
||||||
@ -1709,12 +1709,12 @@ func (r *ClickHouseReader) GetFlamegraphSpansForTrace(ctx context.Context, trace
|
|||||||
}
|
}
|
||||||
|
|
||||||
// metadata calculation
|
// metadata calculation
|
||||||
startTimeUnixNano := uint64(item.TimeUnixNano.UnixNano())
|
startTimeUnixNano := uint64(item.TimeUnixNano.UnixNano())
|
||||||
if startTime == 0 || startTimeUnixNano < startTime {
|
if startTime == 0 || startTimeUnixNano < startTime {
|
||||||
startTime = startTimeUnixNano
|
startTime = startTimeUnixNano
|
||||||
}
|
}
|
||||||
if endTime == 0 || ( startTimeUnixNano + jsonItem.DurationNano ) > endTime {
|
if endTime == 0 || (startTimeUnixNano+jsonItem.DurationNano) > endTime {
|
||||||
endTime = (startTimeUnixNano + jsonItem.DurationNano )
|
endTime = (startTimeUnixNano + jsonItem.DurationNano)
|
||||||
}
|
}
|
||||||
if durationNano == 0 || jsonItem.DurationNano > durationNano {
|
if durationNano == 0 || jsonItem.DurationNano > durationNano {
|
||||||
durationNano = jsonItem.DurationNano
|
durationNano = jsonItem.DurationNano
|
||||||
@ -1778,7 +1778,7 @@ func (r *ClickHouseReader) GetFlamegraphSpansForTrace(ctx context.Context, trace
|
|||||||
|
|
||||||
trace.Spans = selectedSpansForRequest
|
trace.Spans = selectedSpansForRequest
|
||||||
trace.StartTimestampMillis = startTime / 1000000
|
trace.StartTimestampMillis = startTime / 1000000
|
||||||
trace.EndTimestampMillis = endTime / 1000000
|
trace.EndTimestampMillis = endTime / 1000000
|
||||||
return trace, nil
|
return trace, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3464,9 +3464,9 @@ func (r *ClickHouseReader) GetLogs(ctx context.Context, params *model.LogsFilter
|
|||||||
"lenFilters": lenFilters,
|
"lenFilters": lenFilters,
|
||||||
}
|
}
|
||||||
if lenFilters != 0 {
|
if lenFilters != 0 {
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3506,9 +3506,9 @@ func (r *ClickHouseReader) TailLogs(ctx context.Context, client *model.LogsTailC
|
|||||||
"lenFilters": lenFilters,
|
"lenFilters": lenFilters,
|
||||||
}
|
}
|
||||||
if lenFilters != 0 {
|
if lenFilters != 0 {
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3598,9 +3598,9 @@ func (r *ClickHouseReader) AggregateLogs(ctx context.Context, params *model.Logs
|
|||||||
"lenFilters": lenFilters,
|
"lenFilters": lenFilters,
|
||||||
}
|
}
|
||||||
if lenFilters != 0 {
|
if lenFilters != 0 {
|
||||||
userEmail, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LOGS_FILTERS, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -125,13 +125,13 @@ func CreateView(ctx context.Context, view v3.SavedView) (string, error) {
|
|||||||
createdAt := time.Now()
|
createdAt := time.Now()
|
||||||
updatedAt := time.Now()
|
updatedAt := time.Now()
|
||||||
|
|
||||||
email, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return "", err
|
return "", fmt.Errorf("error in getting email from context")
|
||||||
}
|
}
|
||||||
|
|
||||||
createBy := email
|
createBy := claims.Email
|
||||||
updatedBy := email
|
updatedBy := claims.Email
|
||||||
|
|
||||||
_, err = db.Exec(
|
_, err = db.Exec(
|
||||||
"INSERT INTO saved_views (uuid, name, category, created_at, created_by, updated_at, updated_by, source_page, tags, data, extra_data) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
"INSERT INTO saved_views (uuid, name, category, created_at, created_by, updated_at, updated_by, source_page, tags, data, extra_data) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
@ -186,13 +186,13 @@ func UpdateView(ctx context.Context, uuid_ string, view v3.SavedView) error {
|
|||||||
return fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
return fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
email, err := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return err
|
return fmt.Errorf("error in getting email from context")
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedAt := time.Now()
|
updatedAt := time.Now()
|
||||||
updatedBy := email
|
updatedBy := claims.Email
|
||||||
|
|
||||||
_, err = db.Exec("UPDATE saved_views SET updated_at = ?, updated_by = ?, name = ?, category = ?, source_page = ?, tags = ?, data = ?, extra_data = ? WHERE uuid = ?",
|
_, err = db.Exec("UPDATE saved_views SET updated_at = ?, updated_by = ?, name = ?, category = ?, source_page = ?, tags = ?, data = ?, extra_data = ? WHERE uuid = ?",
|
||||||
updatedAt, updatedBy, view.Name, view.Category, view.SourcePage, strings.Join(view.Tags, ","), data, view.ExtraData, uuid_)
|
updatedAt, updatedBy, view.Name, view.Category, view.SourcePage, strings.Join(view.Tags, ","), data, view.ExtraData, uuid_)
|
||||||
|
@ -49,6 +49,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/contextlinks"
|
"go.signoz.io/signoz/pkg/query-service/contextlinks"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/postprocess"
|
"go.signoz.io/signoz/pkg/query-service/postprocess"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
@ -126,6 +127,8 @@ type APIHandler struct {
|
|||||||
jobsRepo *inframetrics.JobsRepo
|
jobsRepo *inframetrics.JobsRepo
|
||||||
|
|
||||||
pvcsRepo *inframetrics.PvcsRepo
|
pvcsRepo *inframetrics.PvcsRepo
|
||||||
|
|
||||||
|
JWT *authtypes.JWT
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIHandlerOpts struct {
|
type APIHandlerOpts struct {
|
||||||
@ -165,6 +168,8 @@ type APIHandlerOpts struct {
|
|||||||
UseLogsNewSchema bool
|
UseLogsNewSchema bool
|
||||||
|
|
||||||
UseTraceNewSchema bool
|
UseTraceNewSchema bool
|
||||||
|
|
||||||
|
JWT *authtypes.JWT
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAPIHandler returns an APIHandler
|
// NewAPIHandler returns an APIHandler
|
||||||
@ -237,6 +242,7 @@ func NewAPIHandler(opts APIHandlerOpts) (*APIHandler, error) {
|
|||||||
statefulsetsRepo: statefulsetsRepo,
|
statefulsetsRepo: statefulsetsRepo,
|
||||||
jobsRepo: jobsRepo,
|
jobsRepo: jobsRepo,
|
||||||
pvcsRepo: pvcsRepo,
|
pvcsRepo: pvcsRepo,
|
||||||
|
JWT: opts.JWT,
|
||||||
}
|
}
|
||||||
|
|
||||||
logsQueryBuilder := logsv3.PrepareLogsQuery
|
logsQueryBuilder := logsv3.PrepareLogsQuery
|
||||||
@ -1616,9 +1622,9 @@ func (aH *APIHandler) submitFeedback(w http.ResponseWriter, r *http.Request) {
|
|||||||
"email": email,
|
"email": email,
|
||||||
"message": message,
|
"message": message,
|
||||||
}
|
}
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_INPRODUCT_FEEDBACK, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_INPRODUCT_FEEDBACK, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1628,9 +1634,9 @@ func (aH *APIHandler) registerEvent(w http.ResponseWriter, r *http.Request) {
|
|||||||
if aH.HandleError(w, err, http.StatusBadRequest) {
|
if aH.HandleError(w, err, http.StatusBadRequest) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(request.EventName, request.Attributes, userEmail, request.RateLimited, true)
|
telemetry.GetInstance().SendEvent(request.EventName, request.Attributes, claims.Email, request.RateLimited, true)
|
||||||
aH.WriteJSON(w, r, map[string]string{"data": "Event Processed Successfully"})
|
aH.WriteJSON(w, r, map[string]string{"data": "Event Processed Successfully"})
|
||||||
} else {
|
} else {
|
||||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||||
@ -1734,9 +1740,9 @@ func (aH *APIHandler) getServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"number": len(*result),
|
"number": len(*result),
|
||||||
}
|
}
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_NUMBER_OF_SERVICES, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_NUMBER_OF_SERVICES, data, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["number"] != 0) && (data["number"] != telemetry.DEFAULT_NUMBER_OF_SERVICES) {
|
if (data["number"] != 0) && (data["number"] != telemetry.DEFAULT_NUMBER_OF_SERVICES) {
|
||||||
@ -2160,7 +2166,7 @@ func (aH *APIHandler) loginUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
// req.RefreshToken = c.Value
|
// req.RefreshToken = c.Value
|
||||||
// }
|
// }
|
||||||
|
|
||||||
resp, err := auth.Login(context.Background(), req)
|
resp, err := auth.Login(context.Background(), req, aH.JWT)
|
||||||
if aH.HandleError(w, err, http.StatusUnauthorized) {
|
if aH.HandleError(w, err, http.StatusUnauthorized) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2442,11 +2448,11 @@ func (aH *APIHandler) editOrg(w http.ResponseWriter, r *http.Request) {
|
|||||||
"isAnonymous": req.IsAnonymous,
|
"isAnonymous": req.IsAnonymous,
|
||||||
"organizationName": req.Name,
|
"organizationName": req.Name,
|
||||||
}
|
}
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err != nil {
|
if !ok {
|
||||||
zap.L().Error("failed to get user email from jwt", zap.Error(err))
|
zap.L().Error("failed to get user email from jwt")
|
||||||
}
|
}
|
||||||
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_ORG_SETTINGS, data, userEmail, true, false)
|
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_ORG_SETTINGS, data, claims.Email, true, false)
|
||||||
|
|
||||||
aH.WriteJSON(w, r, map[string]string{"data": "org updated successfully"})
|
aH.WriteJSON(w, r, map[string]string{"data": "org updated successfully"})
|
||||||
}
|
}
|
||||||
@ -5006,8 +5012,8 @@ func sendQueryResultEvents(r *http.Request, result []*v3.Result, queryRangeParam
|
|||||||
|
|
||||||
if len(result) > 0 && (len(result[0].Series) > 0 || len(result[0].List) > 0) {
|
if len(result) > 0 && (len(result[0].Series) > 0 || len(result[0].List) > 0) {
|
||||||
|
|
||||||
userEmail, err := auth.GetEmailFromJwt(r.Context())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if err == nil {
|
if ok {
|
||||||
queryInfoResult := telemetry.GetInstance().CheckQueryInfo(queryRangeParams)
|
queryInfoResult := telemetry.GetInstance().CheckQueryInfo(queryRangeParams)
|
||||||
if queryInfoResult.LogsUsed || queryInfoResult.MetricsUsed || queryInfoResult.TracesUsed {
|
if queryInfoResult.LogsUsed || queryInfoResult.MetricsUsed || queryInfoResult.TracesUsed {
|
||||||
|
|
||||||
@ -5047,7 +5053,7 @@ func sendQueryResultEvents(r *http.Request, result []*v3.Result, queryRangeParam
|
|||||||
"filterApplied": queryInfoResult.FilterApplied,
|
"filterApplied": queryInfoResult.FilterApplied,
|
||||||
"dashboardId": dashboardID,
|
"dashboardId": dashboardID,
|
||||||
"widgetId": widgetID,
|
"widgetId": widgetID,
|
||||||
}, userEmail, true, false)
|
}, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
if alertMatched {
|
if alertMatched {
|
||||||
var alertID string
|
var alertID string
|
||||||
@ -5074,7 +5080,7 @@ func sendQueryResultEvents(r *http.Request, result []*v3.Result, queryRangeParam
|
|||||||
"aggregateAttributeKey": queryInfoResult.AggregateAttributeKey,
|
"aggregateAttributeKey": queryInfoResult.AggregateAttributeKey,
|
||||||
"filterApplied": queryInfoResult.FilterApplied,
|
"filterApplied": queryInfoResult.FilterApplied,
|
||||||
"alertId": alertID,
|
"alertId": alertID,
|
||||||
}, userEmail, true, false)
|
}, claims.Email, true, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/agentConf"
|
"go.signoz.io/signoz/pkg/query-service/agentConf"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,9 +50,9 @@ func (ic *LogParsingPipelineController) ApplyPipelines(
|
|||||||
postable []PostablePipeline,
|
postable []PostablePipeline,
|
||||||
) (*PipelinesResponse, *model.ApiError) {
|
) (*PipelinesResponse, *model.ApiError) {
|
||||||
// get user id from context
|
// get user id from context
|
||||||
userId, authErr := auth.ExtractUserIdFromContext(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if authErr != nil {
|
if !ok {
|
||||||
return nil, model.UnauthorizedError(errors.Wrap(authErr, "failed to get userId from context"))
|
return nil, model.UnauthorizedError(fmt.Errorf("failed to get userId from context"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelines []Pipeline
|
var pipelines []Pipeline
|
||||||
@ -84,7 +84,7 @@ func (ic *LogParsingPipelineController) ApplyPipelines(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare config by calling gen func
|
// prepare config by calling gen func
|
||||||
cfg, err := agentConf.StartNewVersion(ctx, userId, agentConf.ElementTypeLogPipelines, elements)
|
cfg, err := agentConf.StartNewVersion(ctx, claims.UserID, agentConf.ElementTypeLogPipelines, elements)
|
||||||
if err != nil || cfg == nil {
|
if err != nil || cfg == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,14 +45,9 @@ func (r *Repo) insertPipeline(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt, ok := auth.ExtractJwtFromContext(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, model.UnauthorizedError(err)
|
return nil, model.UnauthorizedError(fmt.Errorf("failed to get email from context"))
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := auth.ParseJWT(jwt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, model.UnauthorizedError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insertRow := &Pipeline{
|
insertRow := &Pipeline{
|
||||||
@ -66,7 +61,7 @@ func (r *Repo) insertPipeline(
|
|||||||
Config: postable.Config,
|
Config: postable.Config,
|
||||||
RawConfig: string(rawConfig),
|
RawConfig: string(rawConfig),
|
||||||
Creator: Creator{
|
Creator: Creator{
|
||||||
CreatedBy: claims["email"].(string),
|
CreatedBy: claims.Email,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
"go.signoz.io/signoz/pkg/query-service/app/preferences"
|
||||||
"go.signoz.io/signoz/pkg/signoz"
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.signoz.io/signoz/pkg/web"
|
"go.signoz.io/signoz/pkg/web"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/explorer"
|
"go.signoz.io/signoz/pkg/query-service/app/explorer"
|
||||||
@ -61,6 +62,7 @@ type ServerOptions struct {
|
|||||||
UseLogsNewSchema bool
|
UseLogsNewSchema bool
|
||||||
UseTraceNewSchema bool
|
UseTraceNewSchema bool
|
||||||
SigNoz *signoz.SigNoz
|
SigNoz *signoz.SigNoz
|
||||||
|
Jwt *authtypes.JWT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server runs HTTP, Mux and a grpc server
|
// Server runs HTTP, Mux and a grpc server
|
||||||
@ -193,6 +195,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
FluxInterval: fluxInterval,
|
FluxInterval: fluxInterval,
|
||||||
UseLogsNewSchema: serverOptions.UseLogsNewSchema,
|
UseLogsNewSchema: serverOptions.UseLogsNewSchema,
|
||||||
UseTraceNewSchema: serverOptions.UseTraceNewSchema,
|
UseTraceNewSchema: serverOptions.UseTraceNewSchema,
|
||||||
|
JWT: serverOptions.Jwt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -247,6 +250,7 @@ func (s *Server) createPrivateServer(api *APIHandler) (*http.Server, error) {
|
|||||||
|
|
||||||
r := NewRouter()
|
r := NewRouter()
|
||||||
|
|
||||||
|
r.Use(middleware.NewAuth(zap.L(), s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
r.Use(middleware.NewTimeout(zap.L(),
|
r.Use(middleware.NewTimeout(zap.L(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
@ -277,6 +281,7 @@ func (s *Server) createPublicServer(api *APIHandler, web web.Web) (*http.Server,
|
|||||||
|
|
||||||
r := NewRouter()
|
r := NewRouter()
|
||||||
|
|
||||||
|
r.Use(middleware.NewAuth(zap.L(), s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
r.Use(middleware.NewTimeout(zap.L(),
|
r.Use(middleware.NewTimeout(zap.L(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
@ -286,8 +291,8 @@ func (s *Server) createPublicServer(api *APIHandler, web web.Web) (*http.Server,
|
|||||||
r.Use(middleware.NewLogging(zap.L(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
r.Use(middleware.NewLogging(zap.L(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
||||||
|
|
||||||
// add auth middleware
|
// add auth middleware
|
||||||
getUserFromRequest := func(r *http.Request) (*model.UserPayload, error) {
|
getUserFromRequest := func(ctx context.Context) (*model.UserPayload, error) {
|
||||||
user, err := auth.GetUserFromRequest(r)
|
user, err := auth.GetUserFromReqContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@ -18,6 +17,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
"go.signoz.io/signoz/pkg/query-service/telemetry"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
smtpservice "go.signoz.io/signoz/pkg/query-service/utils/smtpService"
|
smtpservice "go.signoz.io/signoz/pkg/query-service/utils/smtpService"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@ -75,17 +75,12 @@ func Invite(ctx context.Context, req *model.InviteRequest) (*model.InviteRespons
|
|||||||
return nil, errors.Wrap(err, "invalid invite request")
|
return nil, errors.Wrap(err, "invalid invite request")
|
||||||
}
|
}
|
||||||
|
|
||||||
jwtAdmin, ok := ExtractJwtFromContext(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Wrap(err, "failed to extract admin jwt token")
|
return nil, errors.Wrap(err, "failed to extract admin user id")
|
||||||
}
|
}
|
||||||
|
|
||||||
adminUser, err := validateUser(jwtAdmin)
|
au, apiErr := dao.DB().GetUser(ctx, claims.UserID)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to validate admin jwt token")
|
|
||||||
}
|
|
||||||
|
|
||||||
au, apiErr := dao.DB().GetUser(ctx, adminUser.Id)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
return nil, errors.Wrap(err, "failed to query admin user from the DB")
|
return nil, errors.Wrap(err, "failed to query admin user from the DB")
|
||||||
}
|
}
|
||||||
@ -123,17 +118,12 @@ func InviteUsers(ctx context.Context, req *model.BulkInviteRequest) (*model.Bulk
|
|||||||
FailedInvites: []model.FailedInvite{},
|
FailedInvites: []model.FailedInvite{},
|
||||||
}
|
}
|
||||||
|
|
||||||
jwtAdmin, ok := ExtractJwtFromContext(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("failed to extract admin jwt token")
|
return nil, errors.New("failed to extract admin user id")
|
||||||
}
|
}
|
||||||
|
|
||||||
adminUser, err := validateUser(jwtAdmin)
|
au, apiErr := dao.DB().GetUser(ctx, claims.UserID)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to validate admin jwt token")
|
|
||||||
}
|
|
||||||
|
|
||||||
au, apiErr := dao.DB().GetUser(ctx, adminUser.Id)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
return nil, errors.Wrap(apiErr.Err, "failed to query admin user from the DB")
|
return nil, errors.Wrap(apiErr.Err, "failed to query admin user from the DB")
|
||||||
}
|
}
|
||||||
@ -550,16 +540,16 @@ func Register(ctx context.Context, req *RegisterRequest) (*model.User, *model.Ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login method returns access and refresh tokens on successful login, else it errors out.
|
// Login method returns access and refresh tokens on successful login, else it errors out.
|
||||||
func Login(ctx context.Context, request *model.LoginRequest) (*model.LoginResponse, error) {
|
func Login(ctx context.Context, request *model.LoginRequest, jwt *authtypes.JWT) (*model.LoginResponse, error) {
|
||||||
zap.L().Debug("Login method called for user", zap.String("email", request.Email))
|
zap.L().Debug("Login method called for user", zap.String("email", request.Email))
|
||||||
|
|
||||||
user, err := authenticateLogin(ctx, request)
|
user, err := authenticateLogin(ctx, request, jwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("Failed to authenticate login request", zap.Error(err))
|
zap.L().Error("Failed to authenticate login request", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userjwt, err := GenerateJWTForUser(&user.User)
|
userjwt, err := GenerateJWTForUser(&user.User, jwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("Failed to generate JWT against login creds", zap.Error(err))
|
zap.L().Error("Failed to generate JWT against login creds", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -576,20 +566,36 @@ func Login(ctx context.Context, request *model.LoginRequest) (*model.LoginRespon
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// authenticateLogin is responsible for querying the DB and validating the credentials.
|
func claimsToUserPayload(claims authtypes.Claims) (*model.UserPayload, error) {
|
||||||
func authenticateLogin(ctx context.Context, req *model.LoginRequest) (*model.UserPayload, error) {
|
user := &model.UserPayload{
|
||||||
|
User: model.User{
|
||||||
|
Id: claims.UserID,
|
||||||
|
GroupId: claims.GroupID,
|
||||||
|
Email: claims.Email,
|
||||||
|
OrgId: claims.OrgID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticateLogin is responsible for querying the DB and validating the credentials.
|
||||||
|
func authenticateLogin(ctx context.Context, req *model.LoginRequest, jwt *authtypes.JWT) (*model.UserPayload, error) {
|
||||||
// If refresh token is valid, then simply authorize the login request.
|
// If refresh token is valid, then simply authorize the login request.
|
||||||
if len(req.RefreshToken) > 0 {
|
if len(req.RefreshToken) > 0 {
|
||||||
user, err := validateUser(req.RefreshToken)
|
// parse the refresh token
|
||||||
|
claims, err := jwt.Claims(req.RefreshToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to validate refresh token")
|
return nil, errors.Wrap(err, "failed to parse refresh token")
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.OrgId == "" {
|
if claims.OrgID == "" {
|
||||||
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
return nil, model.UnauthorizedError(errors.New("orgId is missing in the claims"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := claimsToUserPayload(claims)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to convert claims to user payload")
|
||||||
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,34 +624,17 @@ func passwordMatch(hash, password string) bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateJWTForUser(user *model.User) (model.UserJwtObject, error) {
|
func GenerateJWTForUser(user *model.User, jwt *authtypes.JWT) (model.UserJwtObject, error) {
|
||||||
j := model.UserJwtObject{}
|
j := model.UserJwtObject{}
|
||||||
var err error
|
var err error
|
||||||
j.AccessJwtExpiry = time.Now().Add(JwtExpiry).Unix()
|
j.AccessJwtExpiry = time.Now().Add(jwt.JwtExpiry).Unix()
|
||||||
|
j.AccessJwt, err = jwt.AccessToken(user.OrgId, user.Id, user.GroupId, user.Email)
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
||||||
"id": user.Id,
|
|
||||||
"gid": user.GroupId,
|
|
||||||
"email": user.Email,
|
|
||||||
"exp": j.AccessJwtExpiry,
|
|
||||||
"orgId": user.OrgId,
|
|
||||||
})
|
|
||||||
|
|
||||||
j.AccessJwt, err = token.SignedString([]byte(JwtSecret))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return j, errors.Errorf("failed to encode jwt: %v", err)
|
return j, errors.Errorf("failed to encode jwt: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
j.RefreshJwtExpiry = time.Now().Add(JwtRefresh).Unix()
|
j.RefreshJwtExpiry = time.Now().Add(jwt.JwtRefresh).Unix()
|
||||||
token = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
j.RefreshJwt, err = jwt.RefreshToken(user.OrgId, user.Id, user.GroupId, user.Email)
|
||||||
"id": user.Id,
|
|
||||||
"gid": user.GroupId,
|
|
||||||
"email": user.Email,
|
|
||||||
"exp": j.RefreshJwtExpiry,
|
|
||||||
"orgId": user.OrgId,
|
|
||||||
})
|
|
||||||
|
|
||||||
j.RefreshJwt, err = token.SignedString([]byte(JwtSecret))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return j, errors.Errorf("failed to encode jwt: %v", err)
|
return j, errors.Errorf("failed to encode jwt: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
jwtmiddleware "github.com/auth0/go-jwt-middleware"
|
|
||||||
"github.com/golang-jwt/jwt"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
JwtSecret string
|
|
||||||
JwtExpiry = 30 * time.Minute
|
|
||||||
JwtRefresh = 30 * 24 * time.Hour
|
|
||||||
)
|
|
||||||
|
|
||||||
func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
|
|
||||||
// TODO[@vikrantgupta25] : to update this to the claims check function for better integrity of JWT
|
|
||||||
// reference - https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Parser.ParseWithClaims
|
|
||||||
token, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
||||||
return nil, errors.Errorf("unknown signing algo: %v", token.Header["alg"])
|
|
||||||
}
|
|
||||||
return []byte(JwtSecret), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to parse jwt token")
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, ok := token.Claims.(jwt.MapClaims)
|
|
||||||
if !ok || !token.Valid {
|
|
||||||
return nil, errors.Errorf("Not a valid jwt claim")
|
|
||||||
}
|
|
||||||
|
|
||||||
return claims, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateUser(tok string) (*model.UserPayload, error) {
|
|
||||||
claims, err := ParseJWT(tok)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
now := time.Now().Unix()
|
|
||||||
if !claims.VerifyExpiresAt(now, true) {
|
|
||||||
return nil, model.ErrorTokenExpired
|
|
||||||
}
|
|
||||||
|
|
||||||
var orgId string
|
|
||||||
if claims["orgId"] != nil {
|
|
||||||
orgId = claims["orgId"].(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &model.UserPayload{
|
|
||||||
User: model.User{
|
|
||||||
Id: claims["id"].(string),
|
|
||||||
GroupId: claims["gid"].(string),
|
|
||||||
Email: claims["email"].(string),
|
|
||||||
OrgId: orgId,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachJwtToContext attached the jwt token from the request header to the context.
|
|
||||||
func AttachJwtToContext(ctx context.Context, r *http.Request) context.Context {
|
|
||||||
token, err := ExtractJwtFromRequest(r)
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error while getting token from header", zap.Error(err))
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.WithValue(ctx, AccessJwtKey, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractJwtFromContext(ctx context.Context) (string, bool) {
|
|
||||||
jwtToken, ok := ctx.Value(AccessJwtKey).(string)
|
|
||||||
return jwtToken, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractJwtFromRequest(r *http.Request) (string, error) {
|
|
||||||
authHeaderJwt, err := jwtmiddleware.FromAuthHeader(r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(authHeaderJwt) > 0 {
|
|
||||||
return authHeaderJwt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We expect websocket connections to send auth JWT in the
|
|
||||||
// `Sec-Websocket-Protocol` header.
|
|
||||||
//
|
|
||||||
// The standard js websocket API doesn't allow setting headers
|
|
||||||
// other than the `Sec-WebSocket-Protocol` header, which is often
|
|
||||||
// used for auth purposes as a result.
|
|
||||||
return r.Header.Get("Sec-WebSocket-Protocol"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractUserIdFromContext(ctx context.Context) (string, error) {
|
|
||||||
userId := ""
|
|
||||||
jwt, ok := ExtractJwtFromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return "", model.InternalError(fmt.Errorf("failed to extract jwt from context"))
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := ParseJWT(jwt)
|
|
||||||
if err != nil {
|
|
||||||
return "", model.InternalError(fmt.Errorf("failed get claims from jwt %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := claims["id"]; ok {
|
|
||||||
userId = v.(string)
|
|
||||||
}
|
|
||||||
return userId, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetEmailFromJwt(ctx context.Context) (string, error) {
|
|
||||||
jwt, ok := ExtractJwtFromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return "", model.InternalError(fmt.Errorf("failed to extract jwt from context"))
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := ParseJWT(jwt)
|
|
||||||
if err != nil {
|
|
||||||
return "", model.InternalError(fmt.Errorf("failed get claims from jwt %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
return claims["email"].(string), nil
|
|
||||||
}
|
|
@ -2,12 +2,12 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
@ -48,15 +48,19 @@ func InitAuthCache(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserFromRequest(r *http.Request) (*model.UserPayload, error) {
|
func GetUserFromReqContext(ctx context.Context) (*model.UserPayload, error) {
|
||||||
accessJwt, err := ExtractJwtFromRequest(r)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return nil, err
|
return nil, errors.New("no claims found in context")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := validateUser(accessJwt)
|
user := &model.UserPayload{
|
||||||
if err != nil {
|
User: model.User{
|
||||||
return nil, err
|
Id: claims.UserID,
|
||||||
|
GroupId: claims.GroupID,
|
||||||
|
Email: claims.Email,
|
||||||
|
OrgId: claims.OrgID,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/version"
|
"go.signoz.io/signoz/pkg/query-service/version"
|
||||||
"go.signoz.io/signoz/pkg/signoz"
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
@ -98,6 +99,17 @@ func main() {
|
|||||||
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the jwt secret key
|
||||||
|
jwtSecret := os.Getenv("SIGNOZ_JWT_SECRET")
|
||||||
|
|
||||||
|
if len(jwtSecret) == 0 {
|
||||||
|
zap.L().Warn("No JWT secret key is specified.")
|
||||||
|
} else {
|
||||||
|
zap.L().Info("JWT secret key set successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt := authtypes.NewJWT(jwtSecret, 30*time.Minute, 30*24*time.Hour)
|
||||||
|
|
||||||
serverOptions := &app.ServerOptions{
|
serverOptions := &app.ServerOptions{
|
||||||
Config: config,
|
Config: config,
|
||||||
HTTPHostPort: constants.HTTPHostPort,
|
HTTPHostPort: constants.HTTPHostPort,
|
||||||
@ -114,15 +126,7 @@ func main() {
|
|||||||
UseLogsNewSchema: useLogsNewSchema,
|
UseLogsNewSchema: useLogsNewSchema,
|
||||||
UseTraceNewSchema: useTraceNewSchema,
|
UseTraceNewSchema: useTraceNewSchema,
|
||||||
SigNoz: signoz,
|
SigNoz: signoz,
|
||||||
}
|
Jwt: jwt,
|
||||||
|
|
||||||
// Read the jwt secret key
|
|
||||||
auth.JwtSecret = os.Getenv("SIGNOZ_JWT_SECRET")
|
|
||||||
|
|
||||||
if len(auth.JwtSecret) == 0 {
|
|
||||||
zap.L().Warn("No JWT secret key is specified.")
|
|
||||||
} else {
|
|
||||||
zap.L().Info("JWT secret key set successfully.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := app.NewServer(serverOptions)
|
server, err := app.NewServer(serverOptions)
|
||||||
|
@ -10,11 +10,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -267,10 +268,13 @@ func (r *ruleDB) GetPlannedMaintenanceByID(ctx context.Context, id string) (*Pla
|
|||||||
|
|
||||||
func (r *ruleDB) CreatePlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance) (int64, error) {
|
func (r *ruleDB) CreatePlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance) (int64, error) {
|
||||||
|
|
||||||
email, _ := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
maintenance.CreatedBy = email
|
if !ok {
|
||||||
|
return 0, errors.New("no claims found in context")
|
||||||
|
}
|
||||||
|
maintenance.CreatedBy = claims.Email
|
||||||
maintenance.CreatedAt = time.Now()
|
maintenance.CreatedAt = time.Now()
|
||||||
maintenance.UpdatedBy = email
|
maintenance.UpdatedBy = claims.Email
|
||||||
maintenance.UpdatedAt = time.Now()
|
maintenance.UpdatedAt = time.Now()
|
||||||
|
|
||||||
query := "INSERT INTO planned_maintenance (name, description, schedule, alert_ids, created_at, created_by, updated_at, updated_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
query := "INSERT INTO planned_maintenance (name, description, schedule, alert_ids, created_at, created_by, updated_at, updated_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
||||||
@ -298,8 +302,11 @@ func (r *ruleDB) DeletePlannedMaintenance(ctx context.Context, id string) (strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *ruleDB) EditPlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance, id string) (string, error) {
|
func (r *ruleDB) EditPlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance, id string) (string, error) {
|
||||||
email, _ := auth.GetEmailFromJwt(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
maintenance.UpdatedBy = email
|
if !ok {
|
||||||
|
return "", errors.New("no claims found in context")
|
||||||
|
}
|
||||||
|
maintenance.UpdatedBy = claims.Email
|
||||||
maintenance.UpdatedAt = time.Now()
|
maintenance.UpdatedAt = time.Now()
|
||||||
|
|
||||||
query := "UPDATE planned_maintenance SET name=$1, description=$2, schedule=$3, alert_ids=$4, updated_at=$5, updated_by=$6 WHERE id=$7"
|
query := "UPDATE planned_maintenance SET name=$1, description=$2, schedule=$3, alert_ids=$4, updated_at=$5, updated_by=$6 WHERE id=$7"
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/http/middleware"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app"
|
"go.signoz.io/signoz/pkg/query-service/app"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
@ -299,13 +300,16 @@ func NewFilterSuggestionsTestBed(t *testing.T) *FilterSuggestionsTestBed {
|
|||||||
Reader: reader,
|
Reader: reader,
|
||||||
AppDao: dao.DB(),
|
AppDao: dao.DB(),
|
||||||
FeatureFlags: fm,
|
FeatureFlags: fm,
|
||||||
|
JWT: jwt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create a new ApiHandler: %v", err)
|
t.Fatalf("could not create a new ApiHandler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
am := app.NewAuthMiddleware(auth.GetUserFromRequest)
|
//add the jwt middleware
|
||||||
|
router.Use(middleware.NewAuth(zap.L(), jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
|
am := app.NewAuthMiddleware(auth.GetUserFromReqContext)
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterQueryRangeV3Routes(router, am)
|
apiHandler.RegisterQueryRangeV3Routes(router, am)
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||||
opampModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
opampModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
@ -470,6 +469,7 @@ func NewTestbedWithoutOpamp(t *testing.T, testDB *sqlx.DB) *LogPipelinesTestBed
|
|||||||
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
||||||
AppDao: dao.DB(),
|
AppDao: dao.DB(),
|
||||||
LogsParsingPipelineController: controller,
|
LogsParsingPipelineController: controller,
|
||||||
|
JWT: jwt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create a new ApiHandler: %v", err)
|
t.Fatalf("could not create a new ApiHandler: %v", err)
|
||||||
@ -540,7 +540,12 @@ func (tb *LogPipelinesTestBed) PostPipelinesToQSExpectingStatusCode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
respWriter := httptest.NewRecorder()
|
respWriter := httptest.NewRecorder()
|
||||||
ctx := auth.AttachJwtToContext(req.Context(), req)
|
|
||||||
|
ctx, err := tb.apiHandler.JWT.ContextFromRequest(req.Context(), req.Header.Get("Authorization"))
|
||||||
|
if err != nil {
|
||||||
|
tb.t.Fatalf("couldn't get jwt from request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
tb.apiHandler.CreateLogsPipeline(respWriter, req)
|
tb.apiHandler.CreateLogsPipeline(respWriter, req)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/http/middleware"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app"
|
"go.signoz.io/signoz/pkg/query-service/app"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/featureManager"
|
"go.signoz.io/signoz/pkg/query-service/featureManager"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAWSIntegrationAccountLifecycle(t *testing.T) {
|
func TestAWSIntegrationAccountLifecycle(t *testing.T) {
|
||||||
@ -361,13 +363,15 @@ func NewCloudIntegrationsTestBed(t *testing.T, testDB *sqlx.DB) *CloudIntegratio
|
|||||||
AppDao: dao.DB(),
|
AppDao: dao.DB(),
|
||||||
CloudIntegrationsController: controller,
|
CloudIntegrationsController: controller,
|
||||||
FeatureFlags: fm,
|
FeatureFlags: fm,
|
||||||
|
JWT: jwt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create a new ApiHandler: %v", err)
|
t.Fatalf("could not create a new ApiHandler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
am := app.NewAuthMiddleware(auth.GetUserFromRequest)
|
router.Use(middleware.NewAuth(zap.L(), jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
|
am := app.NewAuthMiddleware(auth.GetUserFromReqContext)
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterCloudIntegrationsRoutes(router, am)
|
apiHandler.RegisterCloudIntegrationsRoutes(router, am)
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
mockhouse "github.com/srikanthccv/ClickHouse-go-mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/http/middleware"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app"
|
"go.signoz.io/signoz/pkg/query-service/app"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
||||||
@ -22,6 +23,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.signoz.io/signoz/pkg/query-service/utils"
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Higher level tests for UI facing APIs
|
// Higher level tests for UI facing APIs
|
||||||
@ -568,6 +570,7 @@ func NewIntegrationsTestBed(t *testing.T, testDB *sqlx.DB) *IntegrationsTestBed
|
|||||||
AppDao: dao.DB(),
|
AppDao: dao.DB(),
|
||||||
IntegrationsController: controller,
|
IntegrationsController: controller,
|
||||||
FeatureFlags: fm,
|
FeatureFlags: fm,
|
||||||
|
JWT: jwt,
|
||||||
CloudIntegrationsController: cloudIntegrationsController,
|
CloudIntegrationsController: cloudIntegrationsController,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -575,7 +578,8 @@ func NewIntegrationsTestBed(t *testing.T, testDB *sqlx.DB) *IntegrationsTestBed
|
|||||||
}
|
}
|
||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
am := app.NewAuthMiddleware(auth.GetUserFromRequest)
|
router.Use(middleware.NewAuth(zap.L(), jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
||||||
|
am := app.NewAuthMiddleware(auth.GetUserFromReqContext)
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterIntegrationRoutes(router, am)
|
apiHandler.RegisterIntegrationRoutes(router, am)
|
||||||
|
|
||||||
|
@ -25,9 +25,12 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
"go.signoz.io/signoz/pkg/query-service/interfaces"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
"go.signoz.io/signoz/pkg/types/authtypes"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var jwt = authtypes.NewJWT("secret", 1*time.Hour, 2*time.Hour)
|
||||||
|
|
||||||
func NewMockClickhouseReader(
|
func NewMockClickhouseReader(
|
||||||
t *testing.T, testDB *sqlx.DB, featureFlags interfaces.FeatureLookup,
|
t *testing.T, testDB *sqlx.DB, featureFlags interfaces.FeatureLookup,
|
||||||
) (
|
) (
|
||||||
@ -184,7 +187,7 @@ func AuthenticatedRequestForTest(
|
|||||||
path string,
|
path string,
|
||||||
postData interface{},
|
postData interface{},
|
||||||
) (*http.Request, error) {
|
) (*http.Request, error) {
|
||||||
userJwt, err := auth.GenerateJWTForUser(user)
|
userJwt, err := auth.GenerateJWTForUser(user, jwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
141
pkg/types/authtypes/jwt.go
Normal file
141
pkg/types/authtypes/jwt.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package authtypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jwtClaimsKey struct{}
|
||||||
|
|
||||||
|
type Claims struct {
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
UserID string `json:"id"`
|
||||||
|
GroupID string `json:"gid"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
OrgID string `json:"orgId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWT struct {
|
||||||
|
JwtSecret string
|
||||||
|
JwtExpiry time.Duration
|
||||||
|
JwtRefresh time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJWT(jwtSecret string, jwtExpiry time.Duration, jwtRefresh time.Duration) *JWT {
|
||||||
|
return &JWT{
|
||||||
|
JwtSecret: jwtSecret,
|
||||||
|
JwtExpiry: jwtExpiry,
|
||||||
|
JwtRefresh: jwtRefresh,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBearerAuth(auth string) (string, bool) {
|
||||||
|
const prefix = "Bearer "
|
||||||
|
// Case insensitive prefix match
|
||||||
|
if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth[len(prefix):], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JWT) ContextFromRequest(ctx context.Context, values ...string) (context.Context, error) {
|
||||||
|
var value string
|
||||||
|
for _, v := range values {
|
||||||
|
if v != "" {
|
||||||
|
value = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == "" {
|
||||||
|
return ctx, errors.New("missing Authorization header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse from
|
||||||
|
bearerToken, ok := parseBearerAuth(value)
|
||||||
|
if !ok {
|
||||||
|
// this will take care that if the value is not of type bearer token, directly use it
|
||||||
|
bearerToken = value
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := j.Claims(bearerToken)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewContextWithClaims(ctx, claims), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JWT) Claims(jwtStr string) (Claims, error) {
|
||||||
|
token, err := jwt.ParseWithClaims(jwtStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unknown signing algo: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return []byte(j.JwtSecret), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Claims{}, fmt.Errorf("failed to parse jwt token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type assertion to retrieve claims from the token
|
||||||
|
userClaims, ok := token.Claims.(*Claims)
|
||||||
|
if !ok {
|
||||||
|
return Claims{}, errors.New("failed to retrieve claims from token")
|
||||||
|
}
|
||||||
|
|
||||||
|
return *userClaims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContextWithClaims attaches individual claims to the context.
|
||||||
|
func NewContextWithClaims(ctx context.Context, claims Claims) context.Context {
|
||||||
|
ctx = context.WithValue(ctx, jwtClaimsKey{}, claims)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// signToken creates and signs a JWT token with the given claims
|
||||||
|
func (j *JWT) signToken(claims Claims) (string, error) {
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return token.SignedString([]byte(j.JwtSecret))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessToken creates an access token with the provided claims
|
||||||
|
func (j *JWT) AccessToken(orgId, userId, groupId, email string) (string, error) {
|
||||||
|
claims := Claims{
|
||||||
|
UserID: userId,
|
||||||
|
GroupID: groupId,
|
||||||
|
Email: email,
|
||||||
|
OrgID: orgId,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.JwtExpiry)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return j.signToken(claims)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshToken creates a refresh token with the provided claims
|
||||||
|
func (j *JWT) RefreshToken(orgId, userId, groupId, email string) (string, error) {
|
||||||
|
claims := Claims{
|
||||||
|
UserID: userId,
|
||||||
|
GroupID: groupId,
|
||||||
|
Email: email,
|
||||||
|
OrgID: orgId,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.JwtRefresh)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return j.signToken(claims)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClaimsFromContext(ctx context.Context) (Claims, bool) {
|
||||||
|
claims, ok := ctx.Value(jwtClaimsKey{}).(Claims)
|
||||||
|
return claims, ok
|
||||||
|
}
|
129
pkg/types/authtypes/jwt_test.go
Normal file
129
pkg/types/authtypes/jwt_test.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package authtypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetAccessJwt(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
token, err := jwtService.AccessToken("orgId", "userId", "groupId", "email@example.com")
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRefreshJwt(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
token, err := jwtService.RefreshToken("orgId", "userId", "groupId", "email@example.com")
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJwtClaims(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
|
||||||
|
// Create a valid token
|
||||||
|
claims := Claims{
|
||||||
|
UserID: "userId",
|
||||||
|
GroupID: "groupId",
|
||||||
|
Email: "email@example.com",
|
||||||
|
OrgID: "orgId",
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tokenString, err := jwtService.signToken(claims)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Test retrieving claims from the token
|
||||||
|
retrievedClaims, err := jwtService.Claims(tokenString)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, claims.UserID, retrievedClaims.UserID)
|
||||||
|
assert.Equal(t, claims.GroupID, retrievedClaims.GroupID)
|
||||||
|
assert.Equal(t, claims.Email, retrievedClaims.Email)
|
||||||
|
assert.Equal(t, claims.OrgID, retrievedClaims.OrgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJwtClaimsInvalidToken(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
|
||||||
|
// Test retrieving claims from an invalid token
|
||||||
|
_, err := jwtService.Claims("invalid.token.string")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "token is malformed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJwtClaimsExpiredToken(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
|
||||||
|
// Create an expired token
|
||||||
|
claims := Claims{
|
||||||
|
UserID: "userId",
|
||||||
|
GroupID: "groupId",
|
||||||
|
Email: "email@example.com",
|
||||||
|
OrgID: "orgId",
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(-time.Minute)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tokenString, err := jwtService.signToken(claims)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = jwtService.Claims(tokenString)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "token is expired")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJwtClaimsInvalidSignature(t *testing.T) {
|
||||||
|
jwtService := NewJWT("secret", time.Minute, time.Hour)
|
||||||
|
|
||||||
|
// Create a valid token
|
||||||
|
claims := Claims{
|
||||||
|
UserID: "userId",
|
||||||
|
GroupID: "groupId",
|
||||||
|
Email: "email@example.com",
|
||||||
|
OrgID: "orgId",
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
validToken, err := jwtService.signToken(claims)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Modify the token to create an invalid signature
|
||||||
|
invalidToken := validToken + "tampered"
|
||||||
|
|
||||||
|
// Test retrieving claims from the invalid signature token
|
||||||
|
_, err = jwtService.Claims(invalidToken)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "signature is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseBearerAuth(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
auth string
|
||||||
|
expected string
|
||||||
|
expectOk bool
|
||||||
|
}{
|
||||||
|
{"Bearer validToken", "validToken", true},
|
||||||
|
{"bearer validToken", "validToken", true},
|
||||||
|
{"InvalidToken", "", false},
|
||||||
|
{"Bearer", "", false},
|
||||||
|
{"", "", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.auth, func(t *testing.T) {
|
||||||
|
token, ok := parseBearerAuth(test.auth)
|
||||||
|
assert.Equal(t, test.expected, token)
|
||||||
|
assert.Equal(t, test.expectOk, ok)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
40
pkg/types/authtypes/uuid.go
Normal file
40
pkg/types/authtypes/uuid.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package authtypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type uuidKey struct{}
|
||||||
|
|
||||||
|
type UUID struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUUID() *UUID {
|
||||||
|
return &UUID{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UUID) ContextFromRequest(ctx context.Context, values ...string) (context.Context, error) {
|
||||||
|
var value string
|
||||||
|
for _, v := range values {
|
||||||
|
if v != "" {
|
||||||
|
value = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == "" {
|
||||||
|
return ctx, errors.New("missing Authorization header")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewContextWithUUID(ctx, value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContextWithUUID(ctx context.Context, uuid string) context.Context {
|
||||||
|
return context.WithValue(ctx, uuidKey{}, uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UUIDFromContext(ctx context.Context) (string, bool) {
|
||||||
|
uuid, ok := ctx.Value(uuidKey{}).(string)
|
||||||
|
return uuid, ok
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user