diff --git a/internal/api/authz/authorization.go b/internal/api/authz/authorization.go index 13b1a176b..740bff343 100644 --- a/internal/api/authz/authorization.go +++ b/internal/api/authz/authorization.go @@ -7,14 +7,18 @@ import ( "strings" "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/tracing" ) const ( authenticated = "authenticated" ) -func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID string, verifier *TokenVerifier, authConfig Config, requiredAuthOption Option, method string) (context.Context, error) { - ctx, err := VerifyTokenAndWriteCtxData(ctx, token, orgID, verifier, method) +func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID string, verifier *TokenVerifier, authConfig Config, requiredAuthOption Option, method string) (_ context.Context, err error) { + ctx, span := tracing.NewServerInterceptorSpan(ctx) + defer func() { span.EndWithError(err) }() + + ctx, err = VerifyTokenAndWriteCtxData(ctx, token, orgID, verifier, method) if err != nil { return nil, err } @@ -29,7 +33,9 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID s return nil, err } + ctx, userPermissionSpan := tracing.NewNamedSpan(ctx, "checkUserPermissions") err = checkUserPermissions(req, perms, requiredAuthOption) + userPermissionSpan.EndWithError(err) if err != nil { return nil, err } diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go index 515b08632..576fe2c13 100644 --- a/internal/api/authz/context.go +++ b/internal/api/authz/context.go @@ -6,6 +6,7 @@ import ( "github.com/caos/zitadel/internal/api/grpc" http_util "github.com/caos/zitadel/internal/api/http" "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/tracing" ) type key int @@ -36,6 +37,9 @@ type Grant struct { } func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ context.Context, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + if orgID != "" { err = t.ExistsOrg(ctx, orgID) if err != nil { diff --git a/internal/api/authz/permissions.go b/internal/api/authz/permissions.go index cb1bf2da0..6147deeac 100644 --- a/internal/api/authz/permissions.go +++ b/internal/api/authz/permissions.go @@ -4,9 +4,13 @@ import ( "context" "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/tracing" ) -func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (context.Context, []string, error) { +func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (_ context.Context, _ []string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + ctxData := GetCtxData(ctx) if ctxData.IsZero() { return nil, nil, errors.ThrowUnauthenticated(nil, "AUTH-rKLWEH", "context missing") diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go index 277ff7379..a646cdb8e 100644 --- a/internal/api/authz/token.go +++ b/internal/api/authz/token.go @@ -6,6 +6,7 @@ import ( "sync" caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/tracing" ) const ( @@ -62,7 +63,10 @@ func prefixFromMethod(method string) (string, bool) { return parts[1], true } -func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) (string, error) { +func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) (_ string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + prefix, ok := prefixFromMethod(method) if !ok { return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-GRD2Q", "Errors.Internal") @@ -71,7 +75,6 @@ func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) ( if !ok { return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-G2qrh", "Errors.Internal") } - var err error c := app.(*client) if c.id != "" { return c.id, nil @@ -84,15 +87,22 @@ func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) ( return c.id, nil } -func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*Grant, error) { +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (_ *Grant, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return v.authZRepo.ResolveGrants(ctx) } -func (v *TokenVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) { +func (v *TokenVerifier) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (_ string, _ []string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + return v.authZRepo.ProjectIDAndOriginsByClientID(ctx, clientID) } -func (v *TokenVerifier) ExistsOrg(ctx context.Context, orgID string) error { +func (v *TokenVerifier) ExistsOrg(ctx context.Context, orgID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return v.authZRepo.ExistsOrg(ctx, orgID) } @@ -102,6 +112,9 @@ func (v *TokenVerifier) CheckAuthMethod(method string) (Option, bool) { } func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID, prefLang string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + parts := strings.Split(token, BearerPrefix) if len(parts) != 2 { return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header") diff --git a/internal/api/grpc/client/middleware/tracing.go b/internal/api/grpc/client/middleware/tracing.go index 42edbd14d..e4e93b0e5 100644 --- a/internal/api/grpc/client/middleware/tracing.go +++ b/internal/api/grpc/client/middleware/tracing.go @@ -9,7 +9,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/stats" - "github.com/caos/zitadel/internal/api/http" + grpc_utils "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/tracing" ) @@ -29,7 +29,7 @@ func TracingStatsClient(ignoredMethods ...GRPCMethod) grpc.DialOption { } func DefaultTracingStatsClient() grpc.DialOption { - return TracingStatsClient(http.Healthz, http.Readiness, http.Validation) + return TracingStatsClient(grpc_utils.Healthz, grpc_utils.Readiness, grpc_utils.Validation) } type tracingClientHandler struct { diff --git a/internal/api/grpc/errors/caos_errors.go b/internal/api/grpc/errors/caos_errors.go index 10f4fd3cf..53fd4367a 100644 --- a/internal/api/grpc/errors/caos_errors.go +++ b/internal/api/grpc/errors/caos_errors.go @@ -30,6 +30,9 @@ func CaosToGRPCError(ctx context.Context, err error) error { } func ExtractCaosError(err error) (c codes.Code, msg, id string, ok bool) { + if err == nil { + return codes.OK, "", "", false + } switch caosErr := err.(type) { case *caos_errs.AlreadyExistsError: return codes.AlreadyExists, caosErr.GetMessage(), caosErr.GetID(), true diff --git a/internal/api/grpc/probes.go b/internal/api/grpc/probes.go new file mode 100644 index 000000000..21106cf88 --- /dev/null +++ b/internal/api/grpc/probes.go @@ -0,0 +1,11 @@ +package grpc + +const ( + Healthz = "/Healthz" + Readiness = "/Ready" + Validation = "/Validate" +) + +var ( + Probes = []string{Healthz, Readiness, Validation} +) diff --git a/internal/api/grpc/server/middleware/auth_interceptor.go b/internal/api/grpc/server/middleware/auth_interceptor.go index edc609cc0..48494b25b 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor.go +++ b/internal/api/grpc/server/middleware/auth_interceptor.go @@ -10,6 +10,7 @@ import ( "github.com/caos/zitadel/internal/api/authz" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/tracing" ) func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor { @@ -18,9 +19,13 @@ func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Co } } -func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier *authz.TokenVerifier, authConfig authz.Config) (interface{}, error) { +func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier *authz.TokenVerifier, authConfig authz.Config) (_ interface{}, err error) { + ctx, span := tracing.NewServerInterceptorSpan(ctx) + defer func() { span.EndWithError(err) }() + authOpt, needsToken := verifier.CheckAuthMethod(info.FullMethod) if !needsToken { + span.End() return handler(ctx, req) } @@ -31,10 +36,10 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID) - ctx, err := authz.CheckUserAuthorization(ctx, req, authToken, orgID, verifier, authConfig, authOpt, info.FullMethod) + ctx, err = authz.CheckUserAuthorization(ctx, req, authToken, orgID, verifier, authConfig, authOpt, info.FullMethod) if err != nil { return nil, err } - + span.End() return handler(ctx, req) } diff --git a/internal/api/grpc/server/middleware/tracing.go b/internal/api/grpc/server/middleware/tracing.go index d34de28a5..f27f1b194 100644 --- a/internal/api/grpc/server/middleware/tracing.go +++ b/internal/api/grpc/server/middleware/tracing.go @@ -9,7 +9,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/stats" - "github.com/caos/zitadel/internal/api/http" + grpc_utils "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/tracing" ) @@ -30,7 +30,7 @@ func TracingStatsServer(ignoredMethods ...GRPCMethod) grpc.ServerOption { } func DefaultTracingStatsServer() grpc.ServerOption { - return TracingStatsServer(http.Healthz, http.Readiness, http.Validation) + return TracingStatsServer(grpc_utils.Healthz, grpc_utils.Readiness, grpc_utils.Validation) } type tracingServerHandler struct { diff --git a/internal/api/grpc/server/server.go b/internal/api/grpc/server/server.go index cb86958d1..acb6165c2 100644 --- a/internal/api/grpc/server/server.go +++ b/internal/api/grpc/server/server.go @@ -27,7 +27,7 @@ type Server interface { func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang language.Tag) *grpc.Server { return grpc.NewServer( - middleware.TracingStatsServer(http.Healthz, http.Readiness, http.Validation), + middleware.DefaultTracingStatsServer(), grpc.UnaryInterceptor( grpc_middleware.ChainUnaryServer( middleware.ErrorHandler(), diff --git a/internal/api/http/middleware/trace_interceptor.go b/internal/api/http/middleware/trace_interceptor.go index 6069d63d8..910758977 100644 --- a/internal/api/http/middleware/trace_interceptor.go +++ b/internal/api/http/middleware/trace_interceptor.go @@ -10,3 +10,9 @@ import ( func DefaultTraceHandler(handler http.Handler) http.Handler { return tracing.TraceHandler(handler, http_utils.Probes...) } + +func TraceHandler(ignoredMethods ...string) func(http.Handler) http.Handler { + return func(handler http.Handler) http.Handler { + return tracing.TraceHandler(handler, ignoredMethods...) + } +} diff --git a/internal/api/http/probes.go b/internal/api/http/probes.go index 5752ada51..0290be12a 100644 --- a/internal/api/http/probes.go +++ b/internal/api/http/probes.go @@ -1,9 +1,9 @@ package http const ( - Healthz = "/Healthz" - Readiness = "/Ready" - Validation = "/Validate" + Healthz = "/healthz" + Readiness = "/ready" + Validation = "/validate" ) var ( diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index 47c2e1513..07e2f497b 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -13,10 +13,13 @@ import ( "github.com/caos/zitadel/internal/api/http/middleware" "github.com/caos/zitadel/internal/errors" proj_model "github.com/caos/zitadel/internal/project/model" + "github.com/caos/zitadel/internal/tracing" grant_model "github.com/caos/zitadel/internal/usergrant/model" ) -func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) { +func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (_ op.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id") @@ -37,7 +40,9 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest return AuthRequestFromBusiness(resp) } -func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequest, error) { +func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (_ op.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-D3g21", "no user agent id") @@ -49,7 +54,9 @@ func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequ return AuthRequestFromBusiness(resp) } -func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.AuthRequest, error) { +func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (_ op.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() resp, err := o.repo.AuthRequestByCode(ctx, code) if err != nil { return nil, err @@ -57,7 +64,9 @@ func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.Auth return AuthRequestFromBusiness(resp) } -func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error { +func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return errors.ThrowPreconditionFailed(nil, "OIDC-Dgus2", "no user agent id") @@ -65,11 +74,15 @@ func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error { return o.repo.SaveAuthCode(ctx, id, code, userAgentID) } -func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) error { +func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return o.repo.DeleteAuthRequest(ctx, id) } -func (o *OPStorage) CreateToken(ctx context.Context, req op.TokenRequest) (string, time.Time, error) { +func (o *OPStorage) CreateToken(ctx context.Context, req op.TokenRequest) (_ string, _ time.Time, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() var userAgentID, applicationID string authReq, ok := req.(*AuthRequest) if ok { @@ -93,7 +106,9 @@ func grantsToScopes(grants []*grant_model.UserGrantView) []string { return scopes } -func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) error { +func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id") @@ -105,7 +120,9 @@ func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.Signing o.repo.GetSigningKey(ctx, keyCh, errCh, timer) } -func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) { +func (o *OPStorage) GetKeySet(ctx context.Context) (_ *jose.JSONWebKeySet, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return o.repo.GetKeySet(ctx) } diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go index ab28e36c8..6c53bd0dd 100644 --- a/internal/api/oidc/client.go +++ b/internal/api/oidc/client.go @@ -15,6 +15,7 @@ import ( "github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/errors" proj_model "github.com/caos/zitadel/internal/project/model" + "github.com/caos/zitadel/internal/tracing" user_model "github.com/caos/zitadel/internal/user/model" grant_model "github.com/caos/zitadel/internal/usergrant/model" ) @@ -32,7 +33,9 @@ const ( oidcCtx = "oidc" ) -func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Client, error) { +func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Client, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() client, err := o.repo.ApplicationByClientID(ctx, id) if err != nil { return nil, err @@ -51,7 +54,9 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Clie return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime, allowedScopes) } -func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error) { +func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() key, err := o.repo.MachineKeyByID(ctx, keyID) if err != nil { return nil, err @@ -70,7 +75,9 @@ func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID strin }, nil } -func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) error { +func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() ctx = authz.SetCtxData(ctx, authz.CtxData{ UserID: oidcCtx, OrgID: oidcCtx, @@ -78,7 +85,9 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr return o.repo.AuthorizeOIDCApplication(ctx, id, secret) } -func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (oidc.UserInfo, error) { +func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, origin string) (_ oidc.UserInfo, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() token, err := o.repo.TokenByID(ctx, subject, tokenID) if err != nil { return nil, errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") @@ -95,7 +104,9 @@ func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID, subject, return o.GetUserinfoFromScopes(ctx, token.UserID, token.ApplicationID, token.Scopes) } -func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (oidc.UserInfo, error) { +func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicationID string, scopes []string) (_ oidc.UserInfo, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() user, err := o.repo.UserByID(ctx, userID) if err != nil { return nil, err diff --git a/internal/api/oidc/op.go b/internal/api/oidc/op.go index 519999809..6417b7c7c 100644 --- a/internal/api/oidc/op.go +++ b/internal/api/oidc/op.go @@ -59,6 +59,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re config.OPConfig, newStorage(config.StorageConfig, repo), op.WithHttpInterceptors( + middleware.TraceHandler(), middleware.NoCacheInterceptor, cookieHandler, http_utils.CopyHeadersToContext, diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index f2134b9f4..0876dc90f 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -21,6 +21,7 @@ import ( org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_view_model "github.com/caos/zitadel/internal/org/repository/view/model" project_view_model "github.com/caos/zitadel/internal/project/repository/view/model" + "github.com/caos/zitadel/internal/tracing" user_model "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -91,7 +92,9 @@ func (repo *AuthRequestRepo) Health(ctx context.Context) error { return repo.AuthRequests.Health(ctx) } -func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (_ *model.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() reqID, err := repo.IdGenerator.Next() if err != nil { return nil, err @@ -117,15 +120,21 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod return request, nil } -func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id, userAgentID string) (_ *model.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return repo.getAuthRequestNextSteps(ctx, id, userAgentID, false) } -func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id, userAgentID string) (_ *model.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return repo.getAuthRequestNextSteps(ctx, id, userAgentID, true) } -func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code, userAgentID string) error { +func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, id, userAgentID) if err != nil { return err @@ -134,7 +143,9 @@ func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code, userAge return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) { +func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (_ *model.AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.AuthRequests.GetAuthRequestByCode(ctx, code) if err != nil { return nil, err @@ -147,11 +158,15 @@ func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) return request, nil } -func (repo *AuthRequestRepo) DeleteAuthRequest(ctx context.Context, id string) error { +func (repo *AuthRequestRepo) DeleteAuthRequest(ctx context.Context, id string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() return repo.AuthRequests.DeleteAuthRequest(ctx, id) } -func (repo *AuthRequestRepo) CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error { +func (repo *AuthRequestRepo) CheckLoginName(ctx context.Context, id, loginName, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, id, userAgentID) if err != nil { return err @@ -163,7 +178,9 @@ func (repo *AuthRequestRepo) CheckLoginName(ctx context.Context, id, loginName, return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error { +func (repo *AuthRequestRepo) SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err @@ -175,7 +192,9 @@ func (repo *AuthRequestRepo) SelectExternalIDP(ctx context.Context, authReqID, i return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, externalUser *model.ExternalUser, info *model.BrowserInfo) error { +func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, externalUser *model.ExternalUser, info *model.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err @@ -203,7 +222,9 @@ func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *model. return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAgentID string) error { +func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, id, userAgentID) if err != nil { return err @@ -216,7 +237,9 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) error { +func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, id, userAgentID) if err != nil { return err @@ -227,7 +250,9 @@ func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, pas return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) error { +func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID) if err != nil { return err @@ -238,7 +263,9 @@ func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, us return repo.UserEvents.CheckMfaOTP(ctx, userID, code, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error { +func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err @@ -265,7 +292,9 @@ func (repo *AuthRequestRepo) ResetLinkingUsers(ctx context.Context, authReqID, u return repo.AuthRequests.UpdateAuthRequest(ctx, request) } -func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *user_model.User, externalIDP *user_model.ExternalIDP, orgMember *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error { +func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *user_model.User, externalIDP *user_model.ExternalIDP, orgMember *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() request, err := repo.getAuthRequest(ctx, authReqID, userAgentID) if err != nil { return err diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 471b00a00..d2be7892a 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -2,6 +2,7 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/config/systemdefaults" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" @@ -15,6 +16,7 @@ import ( "github.com/caos/zitadel/internal/eventstore/sdk" org_model "github.com/caos/zitadel/internal/org/model" org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -236,7 +238,9 @@ func (repo *UserRepo) ChangeMyPassword(ctx context.Context, old, new string) err return err } -func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new string) error { +func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID) if errors.IsNotFound(err) { policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID) diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index 2e386289c..359c66ace 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -14,6 +14,7 @@ import ( caos_errs "github.com/caos/zitadel/internal/errors" iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + "github.com/caos/zitadel/internal/tracing" ) type TokenVerifierRepo struct { @@ -59,6 +60,8 @@ func (repo *TokenVerifierRepo) TokenByID(ctx context.Context, tokenID, userID st } func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, prefLang string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() //TODO: use real key tokenIDSubject, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32])) if err != nil { @@ -98,12 +101,15 @@ func (repo *TokenVerifierRepo) ExistsOrg(ctx context.Context, orgID string) erro return err } -func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName string) (string, error) { +func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName string) (_ string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + iam, err := repo.IAMEvents.IAMByID(ctx, repo.IAMID) if err != nil { return "", err } - app, err := repo.View.ApplicationByProjecIDAndAppName(iam.IAMProjectID, appName) + app, err := repo.View.ApplicationByProjecIDAndAppName(ctx, iam.IAMProjectID, appName) if err != nil { return "", err } diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go index 63d028719..bb82b4d62 100644 --- a/internal/authz/repository/eventsourcing/view/application.go +++ b/internal/authz/repository/eventsourcing/view/application.go @@ -1,9 +1,12 @@ package view import ( + "context" + proj_model "github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/repository/view" "github.com/caos/zitadel/internal/project/repository/view/model" + "github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/view/repository" ) @@ -19,7 +22,10 @@ func (v *View) ApplicationByOIDCClientID(clientID string) (*model.ApplicationVie return view.ApplicationByOIDCClientID(v.Db, applicationTable, clientID) } -func (v *View) ApplicationByProjecIDAndAppName(projectID, appName string) (*model.ApplicationView, error) { +func (v *View) ApplicationByProjecIDAndAppName(ctx context.Context, projectID, appName string) (_ *model.ApplicationView, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + return view.ApplicationByProjectIDAndAppName(v.Db, applicationTable, projectID, appName) } diff --git a/internal/iam/repository/eventsourcing/eventstore.go b/internal/iam/repository/eventsourcing/eventstore.go index cd1b3794a..d5236ad22 100644 --- a/internal/iam/repository/eventsourcing/eventstore.go +++ b/internal/iam/repository/eventsourcing/eventstore.go @@ -13,6 +13,7 @@ import ( iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" "github.com/caos/zitadel/internal/id" + "github.com/caos/zitadel/internal/tracing" ) type IAMEventstore struct { @@ -45,7 +46,10 @@ func StartIAM(conf IAMConfig, systemDefaults sd.SystemDefaults) (*IAMEventstore, }, nil } -func (es *IAMEventstore) IAMByID(ctx context.Context, id string) (*iam_model.IAM, error) { +func (es *IAMEventstore) IAMByID(ctx context.Context, id string) (_ *iam_model.IAM, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + iam := es.iamCache.getIAM(id) query, err := IAMByIDQuery(iam.AggregateID, iam.Sequence) diff --git a/internal/org/repository/view/org_view.go b/internal/org/repository/view/org_view.go index d1c2214de..178e6a503 100644 --- a/internal/org/repository/view/org_view.go +++ b/internal/org/repository/view/org_view.go @@ -1,11 +1,12 @@ package view import ( + "github.com/jinzhu/gorm" + caos_errs "github.com/caos/zitadel/internal/errors" org_model "github.com/caos/zitadel/internal/org/model" "github.com/caos/zitadel/internal/org/repository/view/model" "github.com/caos/zitadel/internal/view/repository" - "github.com/jinzhu/gorm" ) func OrgByID(db *gorm.DB, table, orgID string) (*model.OrgView, error) { diff --git a/internal/tracing/http_handler.go b/internal/tracing/http_handler.go index a3b963186..969f5efbf 100644 --- a/internal/tracing/http_handler.go +++ b/internal/tracing/http_handler.go @@ -8,9 +8,7 @@ import ( "go.opencensus.io/trace" ) -func TraceHandler(handler http.Handler, ignoredMethods ...string) http.Handler { - healthEndpoints := strings.Join(ignoredMethods, ";;") - +func TraceHandler(handler http.Handler, ignoredEndpoints ...string) http.Handler { return &ochttp.Handler{ Handler: handler, FormatSpanName: func(r *http.Request) string { @@ -23,8 +21,12 @@ func TraceHandler(handler http.Handler, ignoredMethods ...string) http.Handler { StartOptions: trace.StartOptions{Sampler: Sampler()}, IsHealthEndpoint: func(r *http.Request) bool { - n := strings.Contains(healthEndpoints, r.URL.RequestURI()) - return n + for _, endpoint := range ignoredEndpoints { + if strings.HasPrefix(r.URL.RequestURI(), endpoint) { + return true + } + } + return false }, } } diff --git a/internal/tracing/tracing.go b/internal/tracing/tracing.go index 61fdc4b31..5184ec8ea 100644 --- a/internal/tracing/tracing.go +++ b/internal/tracing/tracing.go @@ -38,6 +38,13 @@ func NewSpan(ctx context.Context) (context.Context, *Span) { return T.NewSpan(ctx, GetCaller()) } +func NewNamedSpan(ctx context.Context, name string) (context.Context, *Span) { + if T == nil { + return ctx, CreateSpan(nil) + } + return T.NewSpan(ctx, name) +} + func NewClientSpan(ctx context.Context) (context.Context, *Span) { if T == nil { return ctx, CreateSpan(nil) @@ -52,18 +59,18 @@ func NewServerSpan(ctx context.Context) (context.Context, *Span) { return T.NewServerSpan(ctx, GetCaller()) } -func NewClientInterceptorSpan(ctx context.Context, name string) (context.Context, *Span) { +func NewClientInterceptorSpan(ctx context.Context) (context.Context, *Span) { if T == nil { return ctx, CreateSpan(nil) } - return T.NewClientInterceptorSpan(ctx, name) + return T.NewClientInterceptorSpan(ctx, GetCaller()) } -func NewServerInterceptorSpan(ctx context.Context, name string) (context.Context, *Span) { +func NewServerInterceptorSpan(ctx context.Context) (context.Context, *Span) { if T == nil { return ctx, CreateSpan(nil) } - return T.NewServerInterceptorSpan(ctx, name) + return T.NewServerInterceptorSpan(ctx, GetCaller()) } func NewSpanHTTP(r *http.Request) (*http.Request, *Span) { diff --git a/internal/ui/login/handler/login.go b/internal/ui/login/handler/login.go index 4322c9c27..149167c41 100644 --- a/internal/ui/login/handler/login.go +++ b/internal/ui/login/handler/login.go @@ -19,7 +19,6 @@ import ( "github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/form" "github.com/caos/zitadel/internal/id" - _ "github.com/caos/zitadel/internal/ui/login/statik" ) @@ -83,7 +82,7 @@ func CreateLogin(config Config, authRepo *eventsourcing.EsRepository, systemDefa security := middleware.SecurityHeaders(csp(), login.cspErrorHandler) userAgentCookie, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode) logging.Log("CONFI-Dvwf2").OnError(err).Panic("unable to create userAgentInterceptor") - login.router = CreateRouter(login, statikFS, csrf, cache, security, userAgentCookie) + login.router = CreateRouter(login, statikFS, csrf, cache, security, userAgentCookie, middleware.TraceHandler(EndpointResources)) login.renderer = CreateRenderer(prefix, statikFS, config.LanguageCookieName, config.DefaultLanguage) login.parser = form.NewParser() return login, handlerPrefix diff --git a/internal/user/repository/eventsourcing/eventstore.go b/internal/user/repository/eventsourcing/eventstore.go index 7d15a6f35..72bb8cbbf 100644 --- a/internal/user/repository/eventsourcing/eventstore.go +++ b/internal/user/repository/eventsourcing/eventstore.go @@ -3,25 +3,25 @@ package eventsourcing import ( "context" "fmt" - iam_model "github.com/caos/zitadel/internal/iam/model" "time" "github.com/caos/logging" "github.com/golang/protobuf/ptypes" - - "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/id" "github.com/pquerna/otp/totp" req_model "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/cache/config" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/id" global_model "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/tracing" usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -554,7 +554,9 @@ func (es *UserEventstore) UserPasswordByID(ctx context.Context, userID string) ( return nil, caos_errs.ThrowNotFound(nil, "EVENT-d8e2", "Errors.User.Password.NotFound") } -func (es *UserEventstore) CheckPassword(ctx context.Context, userID, password string, authRequest *req_model.AuthRequest) error { +func (es *UserEventstore) CheckPassword(ctx context.Context, userID, password string, authRequest *req_model.AuthRequest) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() user, err := es.UserByID(ctx, userID) if err != nil { return err @@ -565,7 +567,10 @@ func (es *UserEventstore) CheckPassword(ctx context.Context, userID, password st if user.Password == nil { return caos_errs.ThrowPreconditionFailed(nil, "EVENT-s35Fa", "Errors.User.Password.Empty") } - if err := crypto.CompareHash(user.Password.SecretCrypto, []byte(password), es.PasswordAlg); err == nil { + ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") + err = crypto.CompareHash(user.Password.SecretCrypto, []byte(password), es.PasswordAlg) + spanPasswordComparison.EndWithError(err) + if err == nil { return es.setPasswordCheckResult(ctx, user, authRequest, PasswordCheckSucceededAggregate) } if err := es.setPasswordCheckResult(ctx, user, authRequest, PasswordCheckFailedAggregate); err != nil { @@ -574,11 +579,13 @@ func (es *UserEventstore) CheckPassword(ctx context.Context, userID, password st return caos_errs.ThrowInvalidArgument(nil, "EVENT-452ad", "Errors.User.Password.Invalid") } -func (es *UserEventstore) setPasswordCheckResult(ctx context.Context, user *usr_model.User, authRequest *req_model.AuthRequest, check func(*es_models.AggregateCreator, *model.User, *model.AuthRequest) es_sdk.AggregateFunc) error { +func (es *UserEventstore) setPasswordCheckResult(ctx context.Context, user *usr_model.User, authRequest *req_model.AuthRequest, check func(*es_models.AggregateCreator, *model.User, *model.AuthRequest) es_sdk.AggregateFunc) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() repoUser := model.UserFromModel(user) repoAuthRequest := model.AuthRequestFromModel(authRequest) agg := check(es.AggregateCreator(), repoUser, repoAuthRequest) - err := es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, agg) + err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, agg) if err != nil { return err } @@ -677,7 +684,9 @@ func (es *UserEventstore) ChangeMachine(ctx context.Context, machine *usr_model. return model.MachineToModel(repoUser.Machine), nil } -func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, old, new string) (*usr_model.Password, error) { +func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, old, new string) (_ *usr_model.Password, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() user, err := es.UserByID(ctx, userID) if err != nil { return nil, err @@ -688,15 +697,20 @@ func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model. if user.Password == nil { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Fds3s", "Errors.User.Password.Empty") } - if err := crypto.CompareHash(user.Password.SecretCrypto, []byte(old), es.PasswordAlg); err != nil { + ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") + err = crypto.CompareHash(user.Password.SecretCrypto, []byte(old), es.PasswordAlg) + spanPasswordComparison.EndWithError(err) + if err != nil { return nil, caos_errs.ThrowInvalidArgument(nil, "EVENT-s56a3", "Errors.User.Password.Invalid") } return es.changedPassword(ctx, user, policy, new, false) } -func (es *UserEventstore) changedPassword(ctx context.Context, user *usr_model.User, policy *iam_model.PasswordComplexityPolicyView, password string, onetime bool) (*usr_model.Password, error) { +func (es *UserEventstore) changedPassword(ctx context.Context, user *usr_model.User, policy *iam_model.PasswordComplexityPolicyView, password string, onetime bool) (_ *usr_model.Password, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() pw := &usr_model.Password{SecretString: password} - err := pw.HashPasswordIfExisting(policy, es.PasswordAlg, onetime) + err = pw.HashPasswordIfExisting(policy, es.PasswordAlg, onetime) if err != nil { return nil, err }