diff --git a/pat/api/http/endpoint.go b/auth/api/http/pats/endpoint.go similarity index 80% rename from pat/api/http/endpoint.go rename to auth/api/http/pats/endpoint.go index 94cbdf5e80b..0fc5233d38a 100644 --- a/pat/api/http/endpoint.go +++ b/auth/api/http/pats/endpoint.go @@ -7,13 +7,13 @@ import ( "context" "github.com/absmach/magistrala/internal/api" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/authn" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/go-kit/kit/endpoint" ) -func createPATEndpoint(svc pat.Service) endpoint.Endpoint { +func createPATEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(createPatReq) if err := req.validate(); err != nil { @@ -25,16 +25,16 @@ func createPATEndpoint(svc pat.Service) endpoint.Endpoint { return nil, svcerr.ErrAuthentication } - pat, err := svc.CreatePAT(ctx, session, req.Name, req.Description, req.Duration, req.Scope) + res, err := svc.CreatePAT(ctx, session, req.Name, req.Description, req.Duration, req.Scope) if err != nil { return nil, err } - return createPatRes{pat}, nil + return createPatRes{res}, nil } } -func retrievePATEndpoint(svc pat.Service) endpoint.Endpoint { +func retrievePATEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(retrievePatReq) if err := req.validate(); err != nil { @@ -46,16 +46,16 @@ func retrievePATEndpoint(svc pat.Service) endpoint.Endpoint { return nil, svcerr.ErrAuthentication } - pat, err := svc.RetrievePAT(ctx, session, req.id) + res, err := svc.RetrievePAT(ctx, session, req.id) if err != nil { return nil, err } - return retrievePatRes{pat}, nil + return retrievePatRes{res}, nil } } -func updatePATNameEndpoint(svc pat.Service) endpoint.Endpoint { +func updatePATNameEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(updatePatNameReq) if err := req.validate(); err != nil { @@ -66,16 +66,16 @@ func updatePATNameEndpoint(svc pat.Service) endpoint.Endpoint { if !ok { return nil, svcerr.ErrAuthentication } - pat, err := svc.UpdatePATName(ctx, session, req.id, req.Name) + res, err := svc.UpdatePATName(ctx, session, req.id, req.Name) if err != nil { return nil, err } - return updatePatNameRes{pat}, nil + return updatePatNameRes{res}, nil } } -func updatePATDescriptionEndpoint(svc pat.Service) endpoint.Endpoint { +func updatePATDescriptionEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(updatePatDescriptionReq) if err := req.validate(); err != nil { @@ -87,16 +87,16 @@ func updatePATDescriptionEndpoint(svc pat.Service) endpoint.Endpoint { return nil, svcerr.ErrAuthentication } - pat, err := svc.UpdatePATDescription(ctx, session, req.id, req.Description) + res, err := svc.UpdatePATDescription(ctx, session, req.id, req.Description) if err != nil { return nil, err } - return updatePatDescriptionRes{pat}, nil + return updatePatDescriptionRes{res}, nil } } -func listPATSEndpoint(svc pat.Service) endpoint.Endpoint { +func listPATSEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(listPatsReq) if err := req.validate(); err != nil { @@ -108,7 +108,7 @@ func listPATSEndpoint(svc pat.Service) endpoint.Endpoint { return nil, svcerr.ErrAuthentication } - pm := pat.PATSPageMeta{ + pm := auth.PATSPageMeta{ Limit: req.limit, Offset: req.offset, } @@ -121,7 +121,7 @@ func listPATSEndpoint(svc pat.Service) endpoint.Endpoint { } } -func deletePATEndpoint(svc pat.Service) endpoint.Endpoint { +func deletePATEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(deletePatReq) if err := req.validate(); err != nil { @@ -141,7 +141,7 @@ func deletePATEndpoint(svc pat.Service) endpoint.Endpoint { } } -func resetPATSecretEndpoint(svc pat.Service) endpoint.Endpoint { +func resetPATSecretEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(resetPatSecretReq) if err := req.validate(); err != nil { @@ -153,16 +153,16 @@ func resetPATSecretEndpoint(svc pat.Service) endpoint.Endpoint { return nil, svcerr.ErrAuthentication } - pat, err := svc.ResetPATSecret(ctx, session, req.id, req.Duration) + res, err := svc.ResetPATSecret(ctx, session, req.id, req.Duration) if err != nil { return nil, err } - return resetPatSecretRes{pat}, nil + return resetPatSecretRes{res}, nil } } -func revokePATSecretEndpoint(svc pat.Service) endpoint.Endpoint { +func revokePATSecretEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(revokePatSecretReq) if err := req.validate(); err != nil { @@ -182,7 +182,7 @@ func revokePATSecretEndpoint(svc pat.Service) endpoint.Endpoint { } } -func addPATScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { +func addPATScopeEntryEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(addPatScopeEntryReq) if err := req.validate(); err != nil { @@ -203,7 +203,7 @@ func addPATScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { } } -func removePATScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { +func removePATScopeEntryEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(removePatScopeEntryReq) if err := req.validate(); err != nil { @@ -223,7 +223,7 @@ func removePATScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { } } -func clearPATAllScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { +func clearPATAllScopeEntryEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(clearAllScopeEntryReq) if err := req.validate(); err != nil { @@ -243,7 +243,7 @@ func clearPATAllScopeEntryEndpoint(svc pat.Service) endpoint.Endpoint { } } -func authorizePATEndpoint(svc pat.Service) endpoint.Endpoint { +func authorizePATEndpoint(svc auth.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(authorizePATReq) if err := req.validate(); err != nil { diff --git a/pat/api/http/requests.go b/auth/api/http/pats/requests.go similarity index 83% rename from pat/api/http/requests.go rename to auth/api/http/pats/requests.go index 1822ec457ef..61584021fdf 100644 --- a/pat/api/http/requests.go +++ b/auth/api/http/pats/requests.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/apiutil" ) @@ -17,7 +17,7 @@ type createPatReq struct { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Duration time.Duration `json:"duration,omitempty"` - Scope pat.Scope `json:"scope,omitempty"` + Scope auth.Scope `json:"scope,omitempty"` } func (cpr *createPatReq) UnmarshalJSON(data []byte) error { @@ -25,7 +25,7 @@ func (cpr *createPatReq) UnmarshalJSON(data []byte) error { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Duration string `json:"duration,omitempty"` - Scope pat.Scope `json:"scope,omitempty"` + Scope auth.Scope `json:"scope,omitempty"` } if err := json.Unmarshal(data, &temp); err != nil { return err @@ -184,10 +184,10 @@ func (req revokePatSecretReq) validate() (err error) { type addPatScopeEntryReq struct { token string id string - PlatformEntityType pat.PlatformEntityType `json:"platform_entity_type,omitempty"` + PlatformEntityType auth.PlatformEntityType `json:"platform_entity_type,omitempty"` OptionalDomainID string `json:"optional_domain_id,omitempty"` - OptionalDomainEntityType pat.DomainEntityType `json:"optional_domain_entity_type,omitempty"` - Operation pat.OperationType `json:"operation,omitempty"` + OptionalDomainEntityType auth.DomainEntityType `json:"optional_domain_entity_type,omitempty"` + Operation auth.OperationType `json:"operation,omitempty"` EntityIDs []string `json:"entity_ids,omitempty"` } @@ -204,15 +204,15 @@ func (apser *addPatScopeEntryReq) UnmarshalJSON(data []byte) error { return err } - pet, err := pat.ParsePlatformEntityType(temp.PlatformEntityType) + pet, err := auth.ParsePlatformEntityType(temp.PlatformEntityType) if err != nil { return err } - odt, err := pat.ParseDomainEntityType(temp.OptionalDomainEntityType) + odt, err := auth.ParseDomainEntityType(temp.OptionalDomainEntityType) if err != nil { return err } - op, err := pat.ParseOperationType(temp.Operation) + op, err := auth.ParseOperationType(temp.Operation) if err != nil { return err } @@ -237,10 +237,10 @@ func (req addPatScopeEntryReq) validate() (err error) { type removePatScopeEntryReq struct { token string id string - PlatformEntityType pat.PlatformEntityType `json:"platform_entity_type,omitempty"` + PlatformEntityType auth.PlatformEntityType `json:"platform_entity_type,omitempty"` OptionalDomainID string `json:"optional_domain_id,omitempty"` - OptionalDomainEntityType pat.DomainEntityType `json:"optional_domain_entity_type,omitempty"` - Operation pat.OperationType `json:"operation,omitempty"` + OptionalDomainEntityType auth.DomainEntityType `json:"optional_domain_entity_type,omitempty"` + Operation auth.OperationType `json:"operation,omitempty"` EntityIDs []string `json:"entity_ids,omitempty"` } @@ -257,15 +257,15 @@ func (rpser *removePatScopeEntryReq) UnmarshalJSON(data []byte) error { return err } - pet, err := pat.ParsePlatformEntityType(temp.PlatformEntityType) + pet, err := auth.ParsePlatformEntityType(temp.PlatformEntityType) if err != nil { return err } - odt, err := pat.ParseDomainEntityType(temp.OptionalDomainEntityType) + odt, err := auth.ParseDomainEntityType(temp.OptionalDomainEntityType) if err != nil { return err } - op, err := pat.ParseOperationType(temp.Operation) + op, err := auth.ParseOperationType(temp.Operation) if err != nil { return err } @@ -304,10 +304,10 @@ func (req clearAllScopeEntryReq) validate() (err error) { type authorizePATReq struct { token string - PlatformEntityType pat.PlatformEntityType `json:"platform_entity_type,omitempty"` + PlatformEntityType auth.PlatformEntityType `json:"platform_entity_type,omitempty"` OptionalDomainID string `json:"optional_domain_id,omitempty"` - OptionalDomainEntityType pat.DomainEntityType `json:"optional_domain_entity_type,omitempty"` - Operation pat.OperationType `json:"operation,omitempty"` + OptionalDomainEntityType auth.DomainEntityType `json:"optional_domain_entity_type,omitempty"` + Operation auth.OperationType `json:"operation,omitempty"` EntityIDs []string `json:"entity_ids,omitempty"` } @@ -327,14 +327,14 @@ func (tcpsr *authorizePATReq) UnmarshalJSON(data []byte) error { tcpsr.OptionalDomainID = temp.OptionalDomainID tcpsr.EntityIDs = temp.EntityIDs - pet, err := pat.ParsePlatformEntityType(temp.PlatformEntityType) + pet, err := auth.ParsePlatformEntityType(temp.PlatformEntityType) if err != nil { return err } tcpsr.PlatformEntityType = pet if temp.OptionalDomainEntityType != "" { - odt, err := pat.ParseDomainEntityType(temp.OptionalDomainEntityType) + odt, err := auth.ParseDomainEntityType(temp.OptionalDomainEntityType) if err != nil { return err } @@ -342,7 +342,7 @@ func (tcpsr *authorizePATReq) UnmarshalJSON(data []byte) error { } if temp.OptionalDomainID != "" { - op, err := pat.ParseOperationType(temp.Operation) + op, err := auth.ParseOperationType(temp.Operation) if err != nil { return err } diff --git a/pat/api/http/responses.go b/auth/api/http/pats/responses.go similarity index 96% rename from pat/api/http/responses.go rename to auth/api/http/pats/responses.go index b2d0fe57dee..01a18722d24 100644 --- a/pat/api/http/responses.go +++ b/auth/api/http/pats/responses.go @@ -7,7 +7,7 @@ import ( "net/http" "github.com/absmach/magistrala" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/auth" ) var ( @@ -24,7 +24,7 @@ var ( ) type createPatRes struct { - pat.PAT + auth.PAT } func (res createPatRes) Code() int { @@ -40,7 +40,7 @@ func (res createPatRes) Empty() bool { } type retrievePatRes struct { - pat.PAT + auth.PAT } func (res retrievePatRes) Code() int { @@ -56,7 +56,7 @@ func (res retrievePatRes) Empty() bool { } type updatePatNameRes struct { - pat.PAT + auth.PAT } func (res updatePatNameRes) Code() int { @@ -72,7 +72,7 @@ func (res updatePatNameRes) Empty() bool { } type updatePatDescriptionRes struct { - pat.PAT + auth.PAT } func (res updatePatDescriptionRes) Code() int { @@ -88,7 +88,7 @@ func (res updatePatDescriptionRes) Empty() bool { } type listPatsRes struct { - pat.PATSPage + auth.PATSPage } func (res listPatsRes) Code() int { @@ -118,7 +118,7 @@ func (res deletePatRes) Empty() bool { } type resetPatSecretRes struct { - pat.PAT + auth.PAT } func (res resetPatSecretRes) Code() int { @@ -148,7 +148,7 @@ func (res revokePatSecretRes) Empty() bool { } type addPatScopeEntryRes struct { - pat.Scope + auth.Scope } func (res addPatScopeEntryRes) Code() int { @@ -164,7 +164,7 @@ func (res addPatScopeEntryRes) Empty() bool { } type removePatScopeEntryRes struct { - pat.Scope + auth.Scope } func (res removePatScopeEntryRes) Code() int { diff --git a/pat/api/http/transport.go b/auth/api/http/pats/transport.go similarity index 98% rename from pat/api/http/transport.go rename to auth/api/http/pats/transport.go index 95d0f45efaf..9fcd259712f 100644 --- a/pat/api/http/transport.go +++ b/auth/api/http/pats/transport.go @@ -10,8 +10,8 @@ import ( "net/http" "strings" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/internal/api" - "github.com/absmach/magistrala/pat" "github.com/absmach/magistrala/pkg/apiutil" mgauthn "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/pkg/errors" @@ -25,7 +25,7 @@ const ( ) // MakeHandler returns a HTTP handler for API endpoints. -func MakeHandler(svc pat.Service, mux *chi.Mux, authn mgauthn.Authentication, logger *slog.Logger) *chi.Mux { +func MakeHandler(svc auth.Service, mux *chi.Mux, authn mgauthn.Authentication, logger *slog.Logger) *chi.Mux { opts := []kithttp.ServerOption{ kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)), } diff --git a/auth/api/http/transport.go b/auth/api/http/transport.go index 27d02149343..d8987b6bf5c 100644 --- a/auth/api/http/transport.go +++ b/auth/api/http/transport.go @@ -8,16 +8,20 @@ import ( "github.com/absmach/magistrala" "github.com/absmach/magistrala/auth" + mgauthn "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/auth/api/http/keys" "github.com/go-chi/chi/v5" + "github.com/absmach/magistrala/auth/api/http/pats" "github.com/prometheus/client_golang/prometheus/promhttp" ) // MakeHandler returns a HTTP handler for API endpoints. -func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string) http.Handler { +func MakeHandler(svc auth.Service, authn mgauthn.Authentication, logger *slog.Logger, instanceID string) http.Handler { mux := chi.NewRouter() mux = keys.MakeHandler(svc, mux, logger) + mux = pats.MakeHandler(svc, mux, authn,logger) + mux.Get("/health", magistrala.Health("auth", instanceID)) mux.Handle("/metrics", promhttp.Handler()) diff --git a/auth/api/logging.go b/auth/api/logging.go index c53bbc4cd95..5d997daf45e 100644 --- a/auth/api/logging.go +++ b/auth/api/logging.go @@ -11,6 +11,7 @@ import ( "time" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/pkg/policies" ) @@ -124,3 +125,253 @@ func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy) }(time.Now()) return lm.svc.Authorize(ctx, pr) } + +func (lm *loggingMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope auth.Scope) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("name", name), + slog.String("description", description), + slog.String("pat_duration", duration.String()), + slog.String("scope", scope.String()), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Create PAT failed to complete successfully", args...) + return + } + lm.logger.Info("Create PAT completed successfully", args...) + }(time.Now()) + return lm.svc.CreatePAT(ctx, session, name, description, duration, scope) +} + +func (lm *loggingMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + slog.String("name", name), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Update PAT name failed to complete successfully", args...) + return + } + lm.logger.Info("Update PAT name completed successfully", args...) + }(time.Now()) + return lm.svc.UpdatePATName(ctx, session, patID, name) +} + +func (lm *loggingMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + slog.String("description", description), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Update PAT description failed to complete successfully", args...) + return + } + lm.logger.Info("Update PAT description completed successfully", args...) + }(time.Now()) + return lm.svc.UpdatePATDescription(ctx, session, patID, description) +} + +func (lm *loggingMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Retrieve PAT failed to complete successfully", args...) + return + } + lm.logger.Info("Retrieve PAT completed successfully", args...) + }(time.Now()) + return lm.svc.RetrievePAT(ctx, session, patID) +} + +func (lm *loggingMiddleware) ListPATS(ctx context.Context, session authn.Session, pm auth.PATSPageMeta) (pp auth.PATSPage, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.Uint64("limit", pm.Limit), + slog.Uint64("offset", pm.Offset), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("List PATS failed to complete successfully", args...) + return + } + lm.logger.Info("List PATS completed successfully", args...) + }(time.Now()) + return lm.svc.ListPATS(ctx, session, pm) +} + +func (lm *loggingMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) (err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Delete PAT failed to complete successfully", args...) + return + } + lm.logger.Info("Delete PAT completed successfully", args...) + }(time.Now()) + return lm.svc.DeletePAT(ctx, session, patID) +} + +func (lm *loggingMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + slog.String("pat_duration", duration.String()), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Reset PAT secret failed to complete successfully", args...) + return + } + lm.logger.Info("Reset PAT secret completed successfully", args...) + }(time.Now()) + return lm.svc.ResetPATSecret(ctx, session, patID, duration) +} + +func (lm *loggingMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) (err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Revoke PAT secret failed to complete successfully", args...) + return + } + lm.logger.Info("Revoke PAT secret completed successfully", args...) + }(time.Now()) + return lm.svc.RevokePATSecret(ctx, session, patID) +} + +func (lm *loggingMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (sc auth.Scope, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + slog.String("platform_entity_type", platformEntityType.String()), + slog.String("optional_domain_id", optionalDomainID), + slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), + slog.String("operation", operation.String()), + slog.Any("entities", entityIDs), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Add entry to PAT scope failed to complete successfully", args...) + return + } + lm.logger.Info("Add entry to PAT scope completed successfully", args...) + }(time.Now()) + return lm.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (lm *loggingMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (sc auth.Scope, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + slog.String("platform_entity_type", platformEntityType.String()), + slog.String("optional_domain_id", optionalDomainID), + slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), + slog.String("operation", operation.String()), + slog.Any("entities", entityIDs), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Remove entry from PAT scope failed to complete successfully", args...) + return + } + lm.logger.Info("Remove entry from PAT scope completed successfully", args...) + }(time.Now()) + return lm.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (lm *loggingMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) (err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("pat_id", patID), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Clear all entry from PAT scope failed to complete successfully", args...) + return + } + lm.logger.Info("Clear all entry from PAT scope completed successfully", args...) + }(time.Now()) + return lm.svc.ClearPATAllScopeEntry(ctx, session, patID) +} + +func (lm *loggingMiddleware) IdentifyPAT(ctx context.Context, paToken string) (pa auth.PAT, err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Identify PAT failed to complete successfully", args...) + return + } + lm.logger.Info("Identify PAT completed successfully", args...) + }(time.Now()) + return lm.svc.IdentifyPAT(ctx, paToken) +} + +func (lm *loggingMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("platform_entity_type", platformEntityType.String()), + slog.String("optional_domain_id", optionalDomainID), + slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), + slog.String("operation", operation.String()), + slog.Any("entities", entityIDs), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Authorize PAT failed complete successfully", args...) + return + } + lm.logger.Info("Authorize PAT completed successfully", args...) + }(time.Now()) + return lm.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (lm *loggingMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (err error) { + defer func(begin time.Time) { + args := []any{ + slog.String("duration", time.Since(begin).String()), + slog.String("user_id", userID), + slog.String("pat_id", patID), + slog.String("platform_entity_type", platformEntityType.String()), + slog.String("optional_domain_id", optionalDomainID), + slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), + slog.String("operation", operation.String()), + slog.Any("entities", entityIDs), + } + if err != nil { + args = append(args, slog.Any("error", err)) + lm.logger.Warn("Check PAT failed complete successfully", args...) + return + } + lm.logger.Info("Check PAT completed successfully", args...) + }(time.Now()) + return lm.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} diff --git a/auth/api/metrics.go b/auth/api/metrics.go index 7048ee3ca51..89d115f5420 100644 --- a/auth/api/metrics.go +++ b/auth/api/metrics.go @@ -10,6 +10,7 @@ import ( "time" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/pkg/policies" "github.com/go-kit/kit/metrics" ) @@ -74,3 +75,115 @@ func (ms *metricsMiddleware) Authorize(ctx context.Context, pr policies.Policy) }(time.Now()) return ms.svc.Authorize(ctx, pr) } + +func (ms *metricsMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope auth.Scope) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "create_pat").Add(1) + ms.latency.With("method", "create_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.CreatePAT(ctx, session, name, description, duration, scope) +} + +func (ms *metricsMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "update_pat_name").Add(1) + ms.latency.With("method", "update_pat_name").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.UpdatePATName(ctx, session, patID, name) +} + +func (ms *metricsMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "update_pat_description").Add(1) + ms.latency.With("method", "update_pat_description").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.UpdatePATDescription(ctx, session, patID, description) +} + +func (ms *metricsMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "retrieve_pat").Add(1) + ms.latency.With("method", "retrieve_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.RetrievePAT(ctx, session, patID) +} + +func (ms *metricsMiddleware) ListPATS(ctx context.Context, session authn.Session, pm auth.PATSPageMeta) (auth.PATSPage, error) { + defer func(begin time.Time) { + ms.counter.With("method", "list_pats").Add(1) + ms.latency.With("method", "list_pats").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.ListPATS(ctx, session, pm) +} + +func (ms *metricsMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) error { + defer func(begin time.Time) { + ms.counter.With("method", "delete_pat").Add(1) + ms.latency.With("method", "delete_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.DeletePAT(ctx, session, patID) +} + +func (ms *metricsMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "reset_pat_secret").Add(1) + ms.latency.With("method", "reset_pat_secret").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.ResetPATSecret(ctx, session, patID, duration) +} + +func (ms *metricsMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { + defer func(begin time.Time) { + ms.counter.With("method", "revoke_pat_secret").Add(1) + ms.latency.With("method", "revoke_pat_secret").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.RevokePATSecret(ctx, session, patID) +} + +func (ms *metricsMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + defer func(begin time.Time) { + ms.counter.With("method", "add_pat_scope_entry").Add(1) + ms.latency.With("method", "add_pat_scope_entry").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (ms *metricsMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + defer func(begin time.Time) { + ms.counter.With("method", "remove_pat_scope_entry").Add(1) + ms.latency.With("method", "remove_pat_scope_entry").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (ms *metricsMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { + defer func(begin time.Time) { + ms.counter.With("method", "clear_pat_all_scope_entry").Add(1) + ms.latency.With("method", "clear_pat_all_scope_entry").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.ClearPATAllScopeEntry(ctx, session, patID) +} + +func (ms *metricsMiddleware) IdentifyPAT(ctx context.Context, paToken string) (auth.PAT, error) { + defer func(begin time.Time) { + ms.counter.With("method", "identify_pat").Add(1) + ms.latency.With("method", "identify_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.IdentifyPAT(ctx, paToken) +} + +func (ms *metricsMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + defer func(begin time.Time) { + ms.counter.With("method", "authorize_pat").Add(1) + ms.latency.With("method", "authorize_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (ms *metricsMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + defer func(begin time.Time) { + ms.counter.With("method", "check_pat").Add(1) + ms.latency.With("method", "check_pat").Observe(time.Since(begin).Seconds()) + }(time.Now()) + return ms.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} diff --git a/pat/bolt/doc.go b/auth/bolt/doc.go similarity index 100% rename from pat/bolt/doc.go rename to auth/bolt/doc.go diff --git a/pat/bolt/init.go b/auth/bolt/init.go similarity index 100% rename from pat/bolt/init.go rename to auth/bolt/init.go diff --git a/pat/bolt/pat.go b/auth/bolt/pat.go similarity index 77% rename from pat/bolt/pat.go rename to auth/bolt/pat.go index b3af87890b3..4534dc4e85f 100644 --- a/pat/bolt/pat.go +++ b/auth/bolt/pat.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/errors" repoerr "github.com/absmach/magistrala/pkg/errors/repository" bolt "go.etcd.io/bbolt" @@ -52,14 +52,14 @@ type patRepo struct { // NewPATSRepository instantiates a bolt // implementation of PAT repository. -func NewPATSRepository(db *bolt.DB, bucketName string) pat.PATSRepository { +func NewPATSRepository(db *bolt.DB, bucketName string) auth.PATSRepository { return &patRepo{ db: db, bucketName: bucketName, } } -func (pr *patRepo) Save(ctx context.Context, pat pat.PAT) error { +func (pr *patRepo) Save(ctx context.Context, pat auth.PAT) error { idxKey := []byte(pat.User + keySeparator + patKey + keySeparator + pat.ID) kv, err := patToKeyValue(pat) if err != nil { @@ -87,7 +87,7 @@ func (pr *patRepo) Save(ctx context.Context, pat pat.PAT) error { }) } -func (pr *patRepo) Retrieve(ctx context.Context, userID, patID string) (pat.PAT, error) { +func (pr *patRepo) Retrieve(ctx context.Context, userID, patID string) (auth.PAT, error) { prefix := []byte(patID + keySeparator) kv := map[string][]byte{} if err := pr.db.View(func(tx *bolt.Tx) error { @@ -101,7 +101,7 @@ func (pr *patRepo) Retrieve(ctx context.Context, userID, patID string) (pat.PAT, } return nil }); err != nil { - return pat.PAT{}, err + return auth.PAT{}, err } return keyValueToPAT(kv) @@ -126,15 +126,15 @@ func (pr *patRepo) RetrieveSecretAndRevokeStatus(ctx context.Context, userID, pa return secretHash, revoked, nil } -func (pr *patRepo) UpdateName(ctx context.Context, userID, patID, name string) (pat.PAT, error) { +func (pr *patRepo) UpdateName(ctx context.Context, userID, patID, name string) (auth.PAT, error) { return pr.updatePATField(ctx, userID, patID, nameKey, []byte(name)) } -func (pr *patRepo) UpdateDescription(ctx context.Context, userID, patID, description string) (pat.PAT, error) { +func (pr *patRepo) UpdateDescription(ctx context.Context, userID, patID, description string) (auth.PAT, error) { return pr.updatePATField(ctx, userID, patID, descriptionKey, []byte(description)) } -func (pr *patRepo) UpdateTokenHash(ctx context.Context, userID, patID, tokenHash string, expiryAt time.Time) (pat.PAT, error) { +func (pr *patRepo) UpdateTokenHash(ctx context.Context, userID, patID, tokenHash string, expiryAt time.Time) (auth.PAT, error) { prefix := []byte(patID + keySeparator) kv := map[string][]byte{} if err := pr.db.Update(func(tx *bolt.Tx) error { @@ -157,12 +157,12 @@ func (pr *patRepo) UpdateTokenHash(ctx context.Context, userID, patID, tokenHash } return nil }); err != nil { - return pat.PAT{}, err + return auth.PAT{}, err } return keyValueToPAT(kv) } -func (pr *patRepo) RetrieveAll(ctx context.Context, userID string, pm pat.PATSPageMeta) (pat.PATSPage, error) { +func (pr *patRepo) RetrieveAll(ctx context.Context, userID string, pm auth.PATSPageMeta) (auth.PATSPage, error) { prefix := []byte(userID + keySeparator + patKey + keySeparator) patIDs := []string{} @@ -179,14 +179,14 @@ func (pr *patRepo) RetrieveAll(ctx context.Context, userID string, pm pat.PATSPa } return nil }); err != nil { - return pat.PATSPage{}, err + return auth.PATSPage{}, err } total := len(patIDs) - var pats []pat.PAT + var pats []auth.PAT - patsPage := pat.PATSPage{ + patsPage := auth.PATSPage{ Total: uint64(total), Limit: pm.Limit, Offset: pm.Offset, @@ -282,7 +282,7 @@ func (pr *patRepo) Remove(ctx context.Context, userID, patID string) error { return nil } -func (pr *patRepo) AddScopeEntry(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { +func (pr *patRepo) AddScopeEntry(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { prefix := []byte(patID + keySeparator + scopeKey) var rKV map[string][]byte if err := pr.db.Update(func(tx *bolt.Tx) error { @@ -306,15 +306,15 @@ func (pr *patRepo) AddScopeEntry(ctx context.Context, userID, patID string, plat } return nil }); err != nil { - return pat.Scope{}, err + return auth.Scope{}, err } return parseKeyValueToScope(rKV) } -func (pr *patRepo) RemoveScopeEntry(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { +func (pr *patRepo) RemoveScopeEntry(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { if len(entityIDs) == 0 { - return pat.Scope{}, repoerr.ErrMalformedEntity + return auth.Scope{}, repoerr.ErrMalformedEntity } prefix := []byte(patID + keySeparator + scopeKey) var rKV map[string][]byte @@ -339,12 +339,12 @@ func (pr *patRepo) RemoveScopeEntry(ctx context.Context, userID, patID string, p } return nil }); err != nil { - return pat.Scope{}, err + return auth.Scope{}, err } return parseKeyValueToScope(rKV) } -func (pr *patRepo) CheckScopeEntry(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { +func (pr *patRepo) CheckScopeEntry(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { return pr.db.Update(func(tx *bolt.Tx) error { b, err := pr.retrieveUserBucket(tx, userID, patID, repoerr.ErrViewEntity) if err != nil { @@ -373,7 +373,7 @@ func (pr *patRepo) RemoveAllScopeEntry(ctx context.Context, userID, patID string return nil } -func (pr *patRepo) updatePATField(_ context.Context, userID, patID, key string, value []byte) (pat.PAT, error) { +func (pr *patRepo) updatePATField(_ context.Context, userID, patID, key string, value []byte) (auth.PAT, error) { prefix := []byte(patID + keySeparator) kv := map[string][]byte{} if err := pr.db.Update(func(tx *bolt.Tx) error { @@ -393,7 +393,7 @@ func (pr *patRepo) updatePATField(_ context.Context, userID, patID, key string, } return nil }); err != nil { - return pat.PAT{}, err + return auth.PAT{}, err } return keyValueToPAT(kv) } @@ -433,7 +433,7 @@ func (pr *patRepo) retrieveRootBucket(tx *bolt.Tx) (*bolt.Bucket, error) { return rootBucket, nil } -func patToKeyValue(pat pat.PAT) (map[string][]byte, error) { +func patToKeyValue(pat auth.PAT) (map[string][]byte, error) { kv := map[string][]byte{ idKey: []byte(pat.ID), userKey: []byte(pat.User), @@ -457,10 +457,10 @@ func patToKeyValue(pat pat.PAT) (map[string][]byte, error) { return kv, nil } -func scopeToKeyValue(scope pat.Scope) (map[string][]byte, error) { +func scopeToKeyValue(scope auth.Scope) (map[string][]byte, error) { kv := map[string][]byte{} for opType, scopeValue := range scope.Users { - tempKV, err := scopeEntryToKeyValue(pat.PlatformUsersScope, "", pat.DomainNullScope, opType, scopeValue.Values()...) + tempKV, err := scopeEntryToKeyValue(auth.PlatformUsersScope, "", auth.DomainNullScope, opType, scopeValue.Values()...) if err != nil { return nil, err } @@ -470,7 +470,7 @@ func scopeToKeyValue(scope pat.Scope) (map[string][]byte, error) { } for domainID, domainScope := range scope.Domains { for opType, scopeValue := range domainScope.DomainManagement { - tempKV, err := scopeEntryToKeyValue(pat.PlatformDomainsScope, domainID, pat.DomainManagementScope, opType, scopeValue.Values()...) + tempKV, err := scopeEntryToKeyValue(auth.PlatformDomainsScope, domainID, auth.DomainManagementScope, opType, scopeValue.Values()...) if err != nil { return nil, errors.Wrap(repoerr.ErrCreateEntity, err) } @@ -480,7 +480,7 @@ func scopeToKeyValue(scope pat.Scope) (map[string][]byte, error) { } for entityType, scope := range domainScope.Entities { for opType, scopeValue := range scope { - tempKV, err := scopeEntryToKeyValue(pat.PlatformDomainsScope, domainID, entityType, opType, scopeValue.Values()...) + tempKV, err := scopeEntryToKeyValue(auth.PlatformDomainsScope, domainID, entityType, opType, scopeValue.Values()...) if err != nil { return nil, errors.Wrap(repoerr.ErrCreateEntity, err) } @@ -493,7 +493,7 @@ func scopeToKeyValue(scope pat.Scope) (map[string][]byte, error) { return kv, nil } -func scopeEntryToKeyValue(platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (map[string][]byte, error) { +func scopeEntryToKeyValue(platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (map[string][]byte, error) { if len(entityIDs) == 0 { return nil, repoerr.ErrMalformedEntity } @@ -518,7 +518,7 @@ func scopeEntryToKeyValue(platformEntityType pat.PlatformEntityType, optionalDom return kv, nil } -func scopeRootKey(platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType) (string, error) { +func scopeRootKey(platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType) (string, error) { op, err := operation.ValidString() if err != nil { return "", errors.Wrap(repoerr.ErrMalformedEntity, err) @@ -532,9 +532,9 @@ func scopeRootKey(platformEntityType pat.PlatformEntityType, optionalDomainID st rootKey.WriteString(keySeparator) switch platformEntityType { - case pat.PlatformUsersScope: + case auth.PlatformUsersScope: rootKey.WriteString(op) - case pat.PlatformDomainsScope: + case auth.PlatformDomainsScope: if optionalDomainID == "" { return "", fmt.Errorf("failed to add platform %s scope: invalid domain id", platformEntityType.String()) } @@ -554,8 +554,8 @@ func scopeRootKey(platformEntityType pat.PlatformEntityType, optionalDomainID st return rootKey.String(), nil } -func keyValueToBasicPAT(kv map[string][]byte) pat.PAT { - var pat pat.PAT +func keyValueToBasicPAT(kv map[string][]byte) auth.PAT { + var pat auth.PAT for k, v := range kv { switch { case strings.HasSuffix(k, keySeparator+idKey): @@ -583,157 +583,157 @@ func keyValueToBasicPAT(kv map[string][]byte) pat.PAT { return pat } -func keyValueToPAT(kv map[string][]byte) (pat.PAT, error) { - res := keyValueToBasicPAT(kv) +func keyValueToPAT(kv map[string][]byte) (auth.PAT, error) { + pat := keyValueToBasicPAT(kv) scope, err := parseKeyValueToScope(kv) if err != nil { - return pat.PAT{}, err + return auth.PAT{}, err } - res.Scope = scope - return res, nil + pat.Scope = scope + return pat, nil } -func parseKeyValueToScope(kv map[string][]byte) (pat.Scope, error) { - scope := pat.Scope{ - Domains: make(map[string]pat.DomainScope), +func parseKeyValueToScope(kv map[string][]byte) (auth.Scope, error) { + scope := auth.Scope{ + Domains: make(map[string]auth.DomainScope), } for key, value := range kv { if strings.Index(key, keySeparator+scopeKey+keySeparator) > 0 { keyParts := strings.Split(key, keySeparator) - platformEntityType, err := pat.ParsePlatformEntityType(keyParts[2]) + platformEntityType, err := auth.ParsePlatformEntityType(keyParts[2]) if err != nil { - return pat.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) } switch platformEntityType { - case pat.PlatformUsersScope: + case auth.PlatformUsersScope: scope.Users, err = parseOperation(platformEntityType, scope.Users, key, keyParts, value) if err != nil { - return pat.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) } - case pat.PlatformDomainsScope: + case auth.PlatformDomainsScope: if len(keyParts) < 6 { - return pat.Scope{}, fmt.Errorf("invalid scope key format: %s", key) + return auth.Scope{}, fmt.Errorf("invalid scope key format: %s", key) } domainID := keyParts[3] if scope.Domains == nil { - scope.Domains = make(map[string]pat.DomainScope) + scope.Domains = make(map[string]auth.DomainScope) } if _, ok := scope.Domains[domainID]; !ok { - scope.Domains[domainID] = pat.DomainScope{} + scope.Domains[domainID] = auth.DomainScope{} } domainScope := scope.Domains[domainID] entityType := keyParts[4] switch entityType { - case pat.DomainManagementScope.String(): + case auth.DomainManagementScope.String(): domainScope.DomainManagement, err = parseOperation(platformEntityType, domainScope.DomainManagement, key, keyParts, value) if err != nil { - return pat.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) } default: - etype, err := pat.ParseDomainEntityType(entityType) + etype, err := auth.ParseDomainEntityType(entityType) if err != nil { - return pat.Scope{}, fmt.Errorf("key %s invalid entity type %s : %w", key, entityType, err) + return auth.Scope{}, fmt.Errorf("key %s invalid entity type %s : %w", key, entityType, err) } if domainScope.Entities == nil { - domainScope.Entities = make(map[pat.DomainEntityType]pat.OperationScope) + domainScope.Entities = make(map[auth.DomainEntityType]auth.OperationScope) } if _, ok := domainScope.Entities[etype]; !ok { - domainScope.Entities[etype] = pat.OperationScope{} + domainScope.Entities[etype] = auth.OperationScope{} } entityOperationScope := domainScope.Entities[etype] entityOperationScope, err = parseOperation(platformEntityType, entityOperationScope, key, keyParts, value) if err != nil { - return pat.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.Scope{}, errors.Wrap(repoerr.ErrViewEntity, err) } domainScope.Entities[etype] = entityOperationScope } scope.Domains[domainID] = domainScope default: - return pat.Scope{}, errors.Wrap(repoerr.ErrViewEntity, fmt.Errorf("invalid platform entity type : %s", platformEntityType.String())) + return auth.Scope{}, errors.Wrap(repoerr.ErrViewEntity, fmt.Errorf("invalid platform entity type : %s", platformEntityType.String())) } } } return scope, nil } -func parseOperation(platformEntityType pat.PlatformEntityType, opScope pat.OperationScope, key string, keyParts []string, value []byte) (pat.OperationScope, error) { +func parseOperation(platformEntityType auth.PlatformEntityType, opScope auth.OperationScope, key string, keyParts []string, value []byte) (auth.OperationScope, error) { if opScope == nil { - opScope = make(map[pat.OperationType]pat.ScopeValue) + opScope = make(map[auth.OperationType]auth.ScopeValue) } if err := validateOperation(platformEntityType, opScope, key, keyParts, value); err != nil { - return pat.OperationScope{}, err + return auth.OperationScope{}, err } switch string(value) { case string(entityValue): - opType, err := pat.ParseOperationType(keyParts[len(keyParts)-2]) + opType, err := auth.ParseOperationType(keyParts[len(keyParts)-2]) if err != nil { - return pat.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) } entityID := keyParts[len(keyParts)-1] if _, oValueExists := opScope[opType]; !oValueExists { - opScope[opType] = &pat.SelectedIDs{} + opScope[opType] = &auth.SelectedIDs{} } oValue := opScope[opType] if err := oValue.AddValues(entityID); err != nil { - return pat.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity value %v : %w", key, entityID, err) + return auth.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity value %v : %w", key, entityID, err) } opScope[opType] = oValue case string(anyIDValue): - opType, err := pat.ParseOperationType(keyParts[len(keyParts)-1]) + opType, err := auth.ParseOperationType(keyParts[len(keyParts)-1]) if err != nil { - return pat.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) } if oValue, oValueExists := opScope[opType]; oValueExists && oValue != nil { - if _, ok := oValue.(*pat.AnyIDs); !ok { - return pat.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity anyIDs scope value : key already initialized with different type", key) + if _, ok := oValue.(*auth.AnyIDs); !ok { + return auth.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity anyIDs scope value : key already initialized with different type", key) } } - opScope[opType] = &pat.AnyIDs{} + opScope[opType] = &auth.AnyIDs{} case string(selectedIDsValue): - opType, err := pat.ParseOperationType(keyParts[len(keyParts)-1]) + opType, err := auth.ParseOperationType(keyParts[len(keyParts)-1]) if err != nil { - return pat.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) + return auth.OperationScope{}, errors.Wrap(repoerr.ErrViewEntity, err) } oValue, oValueExists := opScope[opType] if oValueExists && oValue != nil { - if _, ok := oValue.(*pat.SelectedIDs); !ok { - return pat.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity selectedIDs scope value : key already initialized with different type", key) + if _, ok := oValue.(*auth.SelectedIDs); !ok { + return auth.OperationScope{}, fmt.Errorf("failed to add scope key %s with entity selectedIDs scope value : key already initialized with different type", key) } } if !oValueExists { - opScope[opType] = &pat.SelectedIDs{} + opScope[opType] = &auth.SelectedIDs{} } default: - return pat.OperationScope{}, fmt.Errorf("key %s have invalid value %v", key, value) + return auth.OperationScope{}, fmt.Errorf("key %s have invalid value %v", key, value) } return opScope, nil } -func validateOperation(platformEntityType pat.PlatformEntityType, _ pat.OperationScope, key string, keyParts []string, value []byte) error { +func validateOperation(platformEntityType auth.PlatformEntityType, opScope auth.OperationScope, key string, keyParts []string, value []byte) error { expectedKeyPartsLength := 0 switch string(value) { case string(entityValue): switch platformEntityType { - case pat.PlatformDomainsScope: + case auth.PlatformDomainsScope: expectedKeyPartsLength = 7 - case pat.PlatformUsersScope: + case auth.PlatformUsersScope: expectedKeyPartsLength = 5 default: return fmt.Errorf("invalid platform entity type : %s", platformEntityType.String()) } case string(selectedIDsValue), string(anyIDValue): switch platformEntityType { - case pat.PlatformDomainsScope: + case auth.PlatformDomainsScope: expectedKeyPartsLength = 6 - case pat.PlatformUsersScope: + case auth.PlatformUsersScope: expectedKeyPartsLength = 4 default: return fmt.Errorf("invalid platform entity type : %s", platformEntityType.String()) diff --git a/pat/hasher.go b/auth/hasher.go similarity index 97% rename from pat/hasher.go rename to auth/hasher.go index b0452c1e1d1..ada2352bbe2 100644 --- a/pat/hasher.go +++ b/auth/hasher.go @@ -1,7 +1,7 @@ // Copyright (c) Abstract Machines // SPDX-License-Identifier: Apache-2.0 -package pat +package auth // Hasher specifies an API for generating hashes of an arbitrary textual // content. diff --git a/pat/hasher/doc.go b/auth/hasher/doc.go similarity index 100% rename from pat/hasher/doc.go rename to auth/hasher/doc.go diff --git a/pat/hasher/hasher.go b/auth/hasher/hasher.go similarity index 95% rename from pat/hasher/hasher.go rename to auth/hasher/hasher.go index 4d74669f02a..c417bf7b80a 100644 --- a/pat/hasher/hasher.go +++ b/auth/hasher/hasher.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/auth" "github.com/absmach/magistrala/pkg/errors" "golang.org/x/crypto/scrypt" ) @@ -24,12 +24,12 @@ var ( errDecode = errors.New("failed to decode") ) -var _ pat.Hasher = (*bcryptHasher)(nil) +var _ auth.Hasher = (*bcryptHasher)(nil) type bcryptHasher struct{} // New instantiates a bcrypt-based hasher implementation. -func New() pat.Hasher { +func New() auth.Hasher { return &bcryptHasher{} } diff --git a/auth/mocks/hasher.go b/auth/mocks/hasher.go new file mode 100644 index 00000000000..4c4425b2570 --- /dev/null +++ b/auth/mocks/hasher.go @@ -0,0 +1,72 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +// Copyright (c) Abstract Machines + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Hasher is an autogenerated mock type for the Hasher type +type Hasher struct { + mock.Mock +} + +// Compare provides a mock function with given fields: _a0, _a1 +func (_m *Hasher) Compare(_a0 string, _a1 string) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Compare") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Hash provides a mock function with given fields: _a0 +func (_m *Hasher) Hash(_a0 string) (string, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Hash") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewHasher creates a new instance of Hasher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewHasher(t interface { + mock.TestingT + Cleanup(func()) +}) *Hasher { + mock := &Hasher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/auth/mocks/pats.go b/auth/mocks/pats.go new file mode 100644 index 00000000000..320c253c2a0 --- /dev/null +++ b/auth/mocks/pats.go @@ -0,0 +1,527 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +// Copyright (c) Abstract Machines + +package mocks + +import ( + auth "github.com/absmach/magistrala/auth" + authn "github.com/absmach/magistrala/pkg/authn" + + context "context" + + mock "github.com/stretchr/testify/mock" + + policies "github.com/absmach/magistrala/pkg/policies" + + time "time" +) + +// Service is an autogenerated mock type for the Service type +type Service struct { + mock.Mock +} + +// AddPATScopeEntry provides a mock function with given fields: ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddPATScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Authorize provides a mock function with given fields: ctx, pr +func (_m *Service) Authorize(ctx context.Context, pr policies.Policy) error { + ret := _m.Called(ctx, pr) + + if len(ret) == 0 { + panic("no return value specified for Authorize") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, policies.Policy) error); ok { + r0 = rf(ctx, pr) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AuthorizePAT provides a mock function with given fields: ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) AuthorizePAT(ctx context.Context, paToken string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AuthorizePAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r0 = rf(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CheckPAT provides a mock function with given fields: ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) CheckPAT(ctx context.Context, userID string, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CheckPAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r0 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ClearPATAllScopeEntry provides a mock function with given fields: ctx, session, patID +func (_m *Service) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for ClearPATAllScopeEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreatePAT provides a mock function with given fields: ctx, session, name, description, duration, scope +func (_m *Service) CreatePAT(ctx context.Context, session authn.Session, name string, description string, duration time.Duration, scope auth.Scope) (auth.PAT, error) { + ret := _m.Called(ctx, session, name, description, duration, scope) + + if len(ret) == 0 { + panic("no return value specified for CreatePAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) (auth.PAT, error)); ok { + return rf(ctx, session, name, description, duration, scope) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) auth.PAT); ok { + r0 = rf(ctx, session, name, description, duration, scope) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) error); ok { + r1 = rf(ctx, session, name, description, duration, scope) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeletePAT provides a mock function with given fields: ctx, session, patID +func (_m *Service) DeletePAT(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for DeletePAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Identify provides a mock function with given fields: ctx, token +func (_m *Service) Identify(ctx context.Context, token string) (auth.Key, error) { + ret := _m.Called(ctx, token) + + if len(ret) == 0 { + panic("no return value specified for Identify") + } + + var r0 auth.Key + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (auth.Key, error)); ok { + return rf(ctx, token) + } + if rf, ok := ret.Get(0).(func(context.Context, string) auth.Key); ok { + r0 = rf(ctx, token) + } else { + r0 = ret.Get(0).(auth.Key) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, token) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// IdentifyPAT provides a mock function with given fields: ctx, paToken +func (_m *Service) IdentifyPAT(ctx context.Context, paToken string) (auth.PAT, error) { + ret := _m.Called(ctx, paToken) + + if len(ret) == 0 { + panic("no return value specified for IdentifyPAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (auth.PAT, error)); ok { + return rf(ctx, paToken) + } + if rf, ok := ret.Get(0).(func(context.Context, string) auth.PAT); ok { + r0 = rf(ctx, paToken) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, paToken) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Issue provides a mock function with given fields: ctx, token, key +func (_m *Service) Issue(ctx context.Context, token string, key auth.Key) (auth.Token, error) { + ret := _m.Called(ctx, token, key) + + if len(ret) == 0 { + panic("no return value specified for Issue") + } + + var r0 auth.Token + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Key) (auth.Token, error)); ok { + return rf(ctx, token, key) + } + if rf, ok := ret.Get(0).(func(context.Context, string, auth.Key) auth.Token); ok { + r0 = rf(ctx, token, key) + } else { + r0 = ret.Get(0).(auth.Token) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, auth.Key) error); ok { + r1 = rf(ctx, token, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListPATS provides a mock function with given fields: ctx, session, pm +func (_m *Service) ListPATS(ctx context.Context, session authn.Session, pm auth.PATSPageMeta) (auth.PATSPage, error) { + ret := _m.Called(ctx, session, pm) + + if len(ret) == 0 { + panic("no return value specified for ListPATS") + } + + var r0 auth.PATSPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, auth.PATSPageMeta) (auth.PATSPage, error)); ok { + return rf(ctx, session, pm) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, auth.PATSPageMeta) auth.PATSPage); ok { + r0 = rf(ctx, session, pm) + } else { + r0 = ret.Get(0).(auth.PATSPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, auth.PATSPageMeta) error); ok { + r1 = rf(ctx, session, pm) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemovePATScopeEntry provides a mock function with given fields: ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RemovePATScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ResetPATSecret provides a mock function with given fields: ctx, session, patID, duration +func (_m *Service) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, duration) + + if len(ret) == 0 { + panic("no return value specified for ResetPATSecret") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, time.Duration) (auth.PAT, error)); ok { + return rf(ctx, session, patID, duration) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, time.Duration) auth.PAT); ok { + r0 = rf(ctx, session, patID, duration) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, time.Duration) error); ok { + r1 = rf(ctx, session, patID, duration) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RetrieveKey provides a mock function with given fields: ctx, token, id +func (_m *Service) RetrieveKey(ctx context.Context, token string, id string) (auth.Key, error) { + ret := _m.Called(ctx, token, id) + + if len(ret) == 0 { + panic("no return value specified for RetrieveKey") + } + + var r0 auth.Key + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.Key, error)); ok { + return rf(ctx, token, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.Key); ok { + r0 = rf(ctx, token, id) + } else { + r0 = ret.Get(0).(auth.Key) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, token, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RetrievePAT provides a mock function with given fields: ctx, session, patID +func (_m *Service) RetrievePAT(ctx context.Context, session authn.Session, patID string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for RetrievePAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) auth.PAT); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok { + r1 = rf(ctx, session, patID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Revoke provides a mock function with given fields: ctx, token, id +func (_m *Service) Revoke(ctx context.Context, token string, id string) error { + ret := _m.Called(ctx, token, id) + + if len(ret) == 0 { + panic("no return value specified for Revoke") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, token, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RevokePATSecret provides a mock function with given fields: ctx, session, patID +func (_m *Service) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for RevokePATSecret") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdatePATDescription provides a mock function with given fields: ctx, session, patID, description +func (_m *Service) UpdatePATDescription(ctx context.Context, session authn.Session, patID string, description string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, description) + + if len(ret) == 0 { + panic("no return value specified for UpdatePATDescription") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID, description) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) auth.PAT); ok { + r0 = rf(ctx, session, patID, description) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = rf(ctx, session, patID, description) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdatePATName provides a mock function with given fields: ctx, session, patID, name +func (_m *Service) UpdatePATName(ctx context.Context, session authn.Session, patID string, name string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, name) + + if len(ret) == 0 { + panic("no return value specified for UpdatePATName") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) auth.PAT); ok { + r0 = rf(ctx, session, patID, name) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = rf(ctx, session, patID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewService(t interface { + mock.TestingT + Cleanup(func()) +}) *Service { + mock := &Service{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/auth/mocks/patsrepo.go b/auth/mocks/patsrepo.go new file mode 100644 index 00000000000..323baca097c --- /dev/null +++ b/auth/mocks/patsrepo.go @@ -0,0 +1,394 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +// Copyright (c) Abstract Machines + +package mocks + +import ( + context "context" + + auth "github.com/absmach/magistrala/auth" + + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// PATSRepository is an autogenerated mock type for the PATSRepository type +type PATSRepository struct { + mock.Mock +} + +// AddScopeEntry provides a mock function with given fields: ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *PATSRepository) AddScopeEntry(ctx context.Context, userID string, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CheckScopeEntry provides a mock function with given fields: ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *PATSRepository) CheckScopeEntry(ctx context.Context, userID string, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CheckScopeEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r0 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reactivate provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) Reactivate(ctx context.Context, userID string, patID string) error { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for Reactivate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Remove provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) Remove(ctx context.Context, userID string, patID string) error { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for Remove") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveAllScopeEntry provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) RemoveAllScopeEntry(ctx context.Context, userID string, patID string) error { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for RemoveAllScopeEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveScopeEntry provides a mock function with given fields: ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *PATSRepository) RemoveScopeEntry(ctx context.Context, userID string, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RemoveScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Retrieve provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) Retrieve(ctx context.Context, userID string, patID string) (auth.PAT, error) { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for Retrieve") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.PAT, error)); ok { + return rf(ctx, userID, patID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.PAT); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, userID, patID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RetrieveAll provides a mock function with given fields: ctx, userID, pm +func (_m *PATSRepository) RetrieveAll(ctx context.Context, userID string, pm auth.PATSPageMeta) (auth.PATSPage, error) { + ret := _m.Called(ctx, userID, pm) + + if len(ret) == 0 { + panic("no return value specified for RetrieveAll") + } + + var r0 auth.PATSPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.PATSPageMeta) (auth.PATSPage, error)); ok { + return rf(ctx, userID, pm) + } + if rf, ok := ret.Get(0).(func(context.Context, string, auth.PATSPageMeta) auth.PATSPage); ok { + r0 = rf(ctx, userID, pm) + } else { + r0 = ret.Get(0).(auth.PATSPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, auth.PATSPageMeta) error); ok { + r1 = rf(ctx, userID, pm) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RetrieveSecretAndRevokeStatus provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) RetrieveSecretAndRevokeStatus(ctx context.Context, userID string, patID string) (string, bool, error) { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for RetrieveSecretAndRevokeStatus") + } + + var r0 string + var r1 bool + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (string, bool, error)); ok { + return rf(ctx, userID, patID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) bool); ok { + r1 = rf(ctx, userID, patID) + } else { + r1 = ret.Get(1).(bool) + } + + if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok { + r2 = rf(ctx, userID, patID) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Revoke provides a mock function with given fields: ctx, userID, patID +func (_m *PATSRepository) Revoke(ctx context.Context, userID string, patID string) error { + ret := _m.Called(ctx, userID, patID) + + if len(ret) == 0 { + panic("no return value specified for Revoke") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, userID, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Save provides a mock function with given fields: ctx, pat +func (_m *PATSRepository) Save(ctx context.Context, pat auth.PAT) error { + ret := _m.Called(ctx, pat) + + if len(ret) == 0 { + panic("no return value specified for Save") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, auth.PAT) error); ok { + r0 = rf(ctx, pat) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateDescription provides a mock function with given fields: ctx, userID, patID, description +func (_m *PATSRepository) UpdateDescription(ctx context.Context, userID string, patID string, description string) (auth.PAT, error) { + ret := _m.Called(ctx, userID, patID, description) + + if len(ret) == 0 { + panic("no return value specified for UpdateDescription") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (auth.PAT, error)); ok { + return rf(ctx, userID, patID, description) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) auth.PAT); ok { + r0 = rf(ctx, userID, patID, description) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, userID, patID, description) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateName provides a mock function with given fields: ctx, userID, patID, name +func (_m *PATSRepository) UpdateName(ctx context.Context, userID string, patID string, name string) (auth.PAT, error) { + ret := _m.Called(ctx, userID, patID, name) + + if len(ret) == 0 { + panic("no return value specified for UpdateName") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (auth.PAT, error)); ok { + return rf(ctx, userID, patID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) auth.PAT); ok { + r0 = rf(ctx, userID, patID, name) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, userID, patID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateTokenHash provides a mock function with given fields: ctx, userID, patID, tokenHash, expiryAt +func (_m *PATSRepository) UpdateTokenHash(ctx context.Context, userID string, patID string, tokenHash string, expiryAt time.Time) (auth.PAT, error) { + ret := _m.Called(ctx, userID, patID, tokenHash, expiryAt) + + if len(ret) == 0 { + panic("no return value specified for UpdateTokenHash") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, time.Time) (auth.PAT, error)); ok { + return rf(ctx, userID, patID, tokenHash, expiryAt) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, time.Time) auth.PAT); ok { + r0 = rf(ctx, userID, patID, tokenHash, expiryAt) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, time.Time) error); ok { + r1 = rf(ctx, userID, patID, tokenHash, expiryAt) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewPATSRepository creates a new instance of PATSRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewPATSRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *PATSRepository { + mock := &PATSRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/auth/mocks/service.go b/auth/mocks/service.go index fae27a98be6..320c253c2a0 100644 --- a/auth/mocks/service.go +++ b/auth/mocks/service.go @@ -5,13 +5,16 @@ package mocks import ( - context "context" - auth "github.com/absmach/magistrala/auth" + authn "github.com/absmach/magistrala/pkg/authn" + + context "context" mock "github.com/stretchr/testify/mock" policies "github.com/absmach/magistrala/pkg/policies" + + time "time" ) // Service is an autogenerated mock type for the Service type @@ -19,6 +22,41 @@ type Service struct { mock.Mock } +// AddPATScopeEntry provides a mock function with given fields: ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddPATScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Authorize provides a mock function with given fields: ctx, pr func (_m *Service) Authorize(ctx context.Context, pr policies.Policy) error { ret := _m.Called(ctx, pr) @@ -37,6 +75,120 @@ func (_m *Service) Authorize(ctx context.Context, pr policies.Policy) error { return r0 } +// AuthorizePAT provides a mock function with given fields: ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) AuthorizePAT(ctx context.Context, paToken string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AuthorizePAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r0 = rf(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CheckPAT provides a mock function with given fields: ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) CheckPAT(ctx context.Context, userID string, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CheckPAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r0 = rf(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ClearPATAllScopeEntry provides a mock function with given fields: ctx, session, patID +func (_m *Service) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for ClearPATAllScopeEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreatePAT provides a mock function with given fields: ctx, session, name, description, duration, scope +func (_m *Service) CreatePAT(ctx context.Context, session authn.Session, name string, description string, duration time.Duration, scope auth.Scope) (auth.PAT, error) { + ret := _m.Called(ctx, session, name, description, duration, scope) + + if len(ret) == 0 { + panic("no return value specified for CreatePAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) (auth.PAT, error)); ok { + return rf(ctx, session, name, description, duration, scope) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) auth.PAT); ok { + r0 = rf(ctx, session, name, description, duration, scope) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, time.Duration, auth.Scope) error); ok { + r1 = rf(ctx, session, name, description, duration, scope) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeletePAT provides a mock function with given fields: ctx, session, patID +func (_m *Service) DeletePAT(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for DeletePAT") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Identify provides a mock function with given fields: ctx, token func (_m *Service) Identify(ctx context.Context, token string) (auth.Key, error) { ret := _m.Called(ctx, token) @@ -65,6 +217,34 @@ func (_m *Service) Identify(ctx context.Context, token string) (auth.Key, error) return r0, r1 } +// IdentifyPAT provides a mock function with given fields: ctx, paToken +func (_m *Service) IdentifyPAT(ctx context.Context, paToken string) (auth.PAT, error) { + ret := _m.Called(ctx, paToken) + + if len(ret) == 0 { + panic("no return value specified for IdentifyPAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (auth.PAT, error)); ok { + return rf(ctx, paToken) + } + if rf, ok := ret.Get(0).(func(context.Context, string) auth.PAT); ok { + r0 = rf(ctx, paToken) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, paToken) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Issue provides a mock function with given fields: ctx, token, key func (_m *Service) Issue(ctx context.Context, token string, key auth.Key) (auth.Token, error) { ret := _m.Called(ctx, token, key) @@ -93,6 +273,97 @@ func (_m *Service) Issue(ctx context.Context, token string, key auth.Key) (auth. return r0, r1 } +// ListPATS provides a mock function with given fields: ctx, session, pm +func (_m *Service) ListPATS(ctx context.Context, session authn.Session, pm auth.PATSPageMeta) (auth.PATSPage, error) { + ret := _m.Called(ctx, session, pm) + + if len(ret) == 0 { + panic("no return value specified for ListPATS") + } + + var r0 auth.PATSPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, auth.PATSPageMeta) (auth.PATSPage, error)); ok { + return rf(ctx, session, pm) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, auth.PATSPageMeta) auth.PATSPage); ok { + r0 = rf(ctx, session, pm) + } else { + r0 = ret.Get(0).(auth.PATSPage) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, auth.PATSPageMeta) error); ok { + r1 = rf(ctx, session, pm) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemovePATScopeEntry provides a mock function with given fields: ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs +func (_m *Service) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + _va := make([]interface{}, len(entityIDs)) + for _i := range entityIDs { + _va[_i] = entityIDs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RemovePATScopeEntry") + } + + var r0 auth.Scope + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) (auth.Scope, error)); ok { + return rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) auth.Scope); ok { + r0 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r0 = ret.Get(0).(auth.Scope) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, auth.PlatformEntityType, string, auth.DomainEntityType, auth.OperationType, ...string) error); ok { + r1 = rf(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ResetPATSecret provides a mock function with given fields: ctx, session, patID, duration +func (_m *Service) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, duration) + + if len(ret) == 0 { + panic("no return value specified for ResetPATSecret") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, time.Duration) (auth.PAT, error)); ok { + return rf(ctx, session, patID, duration) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, time.Duration) auth.PAT); ok { + r0 = rf(ctx, session, patID, duration) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, time.Duration) error); ok { + r1 = rf(ctx, session, patID, duration) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RetrieveKey provides a mock function with given fields: ctx, token, id func (_m *Service) RetrieveKey(ctx context.Context, token string, id string) (auth.Key, error) { ret := _m.Called(ctx, token, id) @@ -121,6 +392,34 @@ func (_m *Service) RetrieveKey(ctx context.Context, token string, id string) (au return r0, r1 } +// RetrievePAT provides a mock function with given fields: ctx, session, patID +func (_m *Service) RetrievePAT(ctx context.Context, session authn.Session, patID string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for RetrievePAT") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) auth.PAT); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok { + r1 = rf(ctx, session, patID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Revoke provides a mock function with given fields: ctx, token, id func (_m *Service) Revoke(ctx context.Context, token string, id string) error { ret := _m.Called(ctx, token, id) @@ -139,6 +438,80 @@ func (_m *Service) Revoke(ctx context.Context, token string, id string) error { return r0 } +// RevokePATSecret provides a mock function with given fields: ctx, session, patID +func (_m *Service) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { + ret := _m.Called(ctx, session, patID) + + if len(ret) == 0 { + panic("no return value specified for RevokePATSecret") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = rf(ctx, session, patID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdatePATDescription provides a mock function with given fields: ctx, session, patID, description +func (_m *Service) UpdatePATDescription(ctx context.Context, session authn.Session, patID string, description string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, description) + + if len(ret) == 0 { + panic("no return value specified for UpdatePATDescription") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID, description) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) auth.PAT); ok { + r0 = rf(ctx, session, patID, description) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = rf(ctx, session, patID, description) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdatePATName provides a mock function with given fields: ctx, session, patID, name +func (_m *Service) UpdatePATName(ctx context.Context, session authn.Session, patID string, name string) (auth.PAT, error) { + ret := _m.Called(ctx, session, patID, name) + + if len(ret) == 0 { + panic("no return value specified for UpdatePATName") + } + + var r0 auth.PAT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (auth.PAT, error)); ok { + return rf(ctx, session, patID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) auth.PAT); ok { + r0 = rf(ctx, session, patID, name) + } else { + r0 = ret.Get(0).(auth.PAT) + } + + if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = rf(ctx, session, patID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewService(t interface { diff --git a/pat/pat.go b/auth/pat.go similarity index 99% rename from pat/pat.go rename to auth/pat.go index 5b9cb080456..6ab57aaacce 100644 --- a/pat/pat.go +++ b/auth/pat.go @@ -1,7 +1,7 @@ // Copyright (c) Abstract Machines // SPDX-License-Identifier: Apache-2.0 -package pat +package auth import ( "context" @@ -665,7 +665,7 @@ func (pat PAT) Expired() bool { // PATS specifies function which are required for Personal access Token implementation. //go:generate mockery --name Service --output=./mocks --filename pats.go --quiet --note "Copyright (c) Abstract Machines" -type Service interface { +type PATS interface { // Create function creates new PAT for given valid inputs. CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope Scope) (PAT, error) diff --git a/auth/service.go b/auth/service.go index 4fd1ceb7ceb..12fc29cc9aa 100644 --- a/auth/service.go +++ b/auth/service.go @@ -5,19 +5,25 @@ package auth import ( "context" + "encoding/base64" + "math/rand" "strings" "time" "github.com/absmach/magistrala" - "github.com/absmach/magistrala/pat" + "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/pkg/errors" svcerr "github.com/absmach/magistrala/pkg/errors/service" "github.com/absmach/magistrala/pkg/policies" + "github.com/google/uuid" ) const ( - recoveryDuration = 5 * time.Minute - defLimit = 100 + recoveryDuration = 5 * time.Minute + defLimit = 100 + randStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&&*|+-=" + patPrefix = "pat" + patSecretSeparator = "_" ) var ( @@ -36,6 +42,17 @@ var ( errRollbackPolicy = errors.New("failed to rollback policy") errRemoveLocalPolicy = errors.New("failed to remove from local policy copy") errRemovePolicyEngine = errors.New("failed to remove from policy engine") + + errMalformedPAT = errors.New("malformed personal access token") + errFailedToParseUUID = errors.New("failed to parse string to UUID") + errInvalidLenFor2UUIDs = errors.New("invalid input length for 2 UUID, excepted 32 byte") + errRevokedPAT = errors.New("revoked pat") + errCreatePAT = errors.New("failed to create PAT") + errUpdatePAT = errors.New("failed to update PAT") + errRetrievePAT = errors.New("failed to retrieve PAT") + errDeletePAT = errors.New("failed to delete PAT") + errRevokePAT = errors.New("failed to revoke PAT") + errClearAllScope = errors.New("failed to clear all entry in scope") ) // Authz represents a authorization service. It exposes @@ -82,14 +99,15 @@ type Authn interface { type Service interface { Authn Authz + PATS } var _ Service = (*service)(nil) type service struct { keys KeyRepository - pats pat.PATSRepository - hasher pat.Hasher + pats PATSRepository + hasher Hasher idProvider magistrala.IDProvider evaluator policies.Evaluator policysvc policies.Service @@ -100,7 +118,7 @@ type service struct { } // New instantiates the auth service implementation. -func New(keys KeyRepository,pats pat.PATSRepository, hasher pat.Hasher, idp magistrala.IDProvider, tokenizer Tokenizer, policyEvaluator policies.Evaluator, policyService policies.Service, loginDuration, refreshDuration, invitationDuration time.Duration) Service { +func New(keys KeyRepository, pats PATSRepository, hasher Hasher, idp magistrala.IDProvider, tokenizer Tokenizer, policyEvaluator policies.Evaluator, policyService policies.Service, loginDuration, refreshDuration, invitationDuration time.Duration) Service { return &service{ tokenizer: tokenizer, keys: keys, @@ -156,7 +174,7 @@ func (svc service) RetrieveKey(ctx context.Context, token, id string) (Key, erro } func (svc service) Identify(ctx context.Context, token string) (Key, error) { - if strings.HasPrefix(token, "pat"+"_") { + if strings.HasPrefix(token, patPrefix+patSecretSeparator) { pat, err := svc.IdentifyPAT(ctx, token) if err != nil { return Key{}, err @@ -467,3 +485,208 @@ func DecodeDomainUserID(domainUserID string) (string, string) { return "", "" } } + +func (svc service) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope Scope) (PAT, error) { + id, err := svc.idProvider.ID() + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrCreateEntity, err) + } + secret, hash, err := svc.generateSecretAndHash(session.UserID, id) + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrCreateEntity, err) + } + + now := time.Now() + pat := PAT{ + ID: id, + User: session.UserID, + Name: name, + Description: description, + Secret: hash, + IssuedAt: now, + ExpiresAt: now.Add(duration), + Scope: scope, + } + if err := svc.pats.Save(ctx, pat); err != nil { + return PAT{}, errors.Wrap(errCreatePAT, err) + } + pat.Secret = secret + return pat, nil +} + +func (svc service) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (PAT, error) { + pat, err := svc.pats.UpdateName(ctx, session.UserID, patID, name) + if err != nil { + return PAT{}, errors.Wrap(errUpdatePAT, err) + } + return pat, nil +} + +func (svc service) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (PAT, error) { + pat, err := svc.pats.UpdateDescription(ctx, session.UserID, patID, description) + if err != nil { + return PAT{}, errors.Wrap(errUpdatePAT, err) + } + return pat, nil +} + +func (svc service) RetrievePAT(ctx context.Context, session authn.Session, patID string) (PAT, error) { + pat, err := svc.pats.Retrieve(ctx, session.UserID, patID) + if err != nil { + return PAT{}, errors.Wrap(errRetrievePAT, err) + } + return pat, nil +} + +func (svc service) ListPATS(ctx context.Context, session authn.Session, pm PATSPageMeta) (PATSPage, error) { + patsPage, err := svc.pats.RetrieveAll(ctx, session.UserID, pm) + if err != nil { + return PATSPage{}, errors.Wrap(errRetrievePAT, err) + } + return patsPage, nil +} + +func (svc service) DeletePAT(ctx context.Context, session authn.Session, patID string) error { + if err := svc.pats.Remove(ctx, session.UserID, patID); err != nil { + return errors.Wrap(errDeletePAT, err) + } + return nil +} + +func (svc service) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (PAT, error) { + // Generate new HashToken take place here + secret, hash, err := svc.generateSecretAndHash(session.UserID, patID) + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) + } + + pat, err := svc.pats.UpdateTokenHash(ctx, session.UserID, patID, hash, time.Now().Add(duration)) + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) + } + + if err := svc.pats.Reactivate(ctx, session.UserID, patID); err != nil { + return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) + } + pat.Secret = secret + pat.Revoked = false + pat.RevokedAt = time.Time{} + return pat, nil +} + +func (svc service) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { + if err := svc.pats.Revoke(ctx, session.UserID, patID); err != nil { + return errors.Wrap(errRevokePAT, err) + } + return nil +} + +func (svc service) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) (Scope, error) { + scope, err := svc.pats.AddScopeEntry(ctx, session.UserID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + if err != nil { + return Scope{}, errors.Wrap(errRevokePAT, err) + } + return scope, nil +} + +func (svc service) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) (Scope, error) { + scope, err := svc.pats.RemoveScopeEntry(ctx, session.UserID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) + if err != nil { + return Scope{}, err + } + return scope, nil +} + +func (svc service) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { + if err := svc.pats.RemoveAllScopeEntry(ctx, session.UserID, patID); err != nil { + return errors.Wrap(errClearAllScope, err) + } + return nil +} + +func (svc service) IdentifyPAT(ctx context.Context, secret string) (PAT, error) { + parts := strings.Split(secret, patSecretSeparator) + if len(parts) != 3 && parts[0] != patPrefix { + return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errMalformedPAT) + } + userID, patID, err := decode(parts[1]) + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errMalformedPAT) + } + secretHash, revoked, err := svc.pats.RetrieveSecretAndRevokeStatus(ctx, userID.String(), patID.String()) + if err != nil { + return PAT{}, errors.Wrap(svcerr.ErrAuthentication, err) + } + if revoked { + return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errRevokedPAT) + } + if err := svc.hasher.Compare(secret, secretHash); err != nil { + return PAT{}, errors.Wrap(svcerr.ErrAuthentication, err) + } + return PAT{ID: patID.String(), User: userID.String()}, nil +} + +func (svc service) AuthorizePAT(ctx context.Context, paToken string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) error { + res, err := svc.IdentifyPAT(ctx, paToken) + if err != nil { + return err + } + if err := svc.pats.CheckScopeEntry(ctx, res.User, res.ID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...); err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } + return nil +} + +func (svc service) CheckPAT(ctx context.Context, userID, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) error { + if err := svc.pats.CheckScopeEntry(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...); err != nil { + return errors.Wrap(svcerr.ErrAuthorization, err) + } + return nil +} + +func (svc service) generateSecretAndHash(userID, patID string) (string, string, error) { + uID, err := uuid.Parse(userID) + if err != nil { + return "", "", errors.Wrap(errFailedToParseUUID, err) + } + pID, err := uuid.Parse(patID) + if err != nil { + return "", "", errors.Wrap(errFailedToParseUUID, err) + } + + secret := patPrefix + patSecretSeparator + encode(uID, pID) + patSecretSeparator + generateRandomString(100) + secretHash, err := svc.hasher.Hash(secret) + return secret, secretHash, err +} + +func encode(userID, patID uuid.UUID) string { + c := append(userID[:], patID[:]...) + return base64.StdEncoding.EncodeToString(c) +} + +func decode(encoded string) (uuid.UUID, uuid.UUID, error) { + data, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return uuid.Nil, uuid.Nil, err + } + + if len(data) != 32 { + return uuid.Nil, uuid.Nil, errInvalidLenFor2UUIDs + } + + var userID, patID uuid.UUID + copy(userID[:], data[:16]) + copy(patID[:], data[16:]) + + return userID, patID, nil +} + +func generateRandomString(n int) string { + letterRunes := []rune(randStr) + rand.New(rand.NewSource(time.Now().UnixNano())) + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} diff --git a/auth/service_test.go b/auth/service_test.go index 698f739fd9d..93f0b9e3ae0 100644 --- a/auth/service_test.go +++ b/auth/service_test.go @@ -53,12 +53,16 @@ var ( krepo *mocks.KeyRepository pService *policymocks.Service pEvaluator *policymocks.Evaluator + patsrepo *mocks.PATSRepository + hasher *mocks.Hasher ) func newService() (auth.Service, string) { krepo = new(mocks.KeyRepository) pService = new(policymocks.Service) pEvaluator = new(policymocks.Evaluator) + patsrepo = new(mocks.PATSRepository) + hasher = new(mocks.Hasher) idProvider := uuid.NewMock() t := jwt.New([]byte(secret)) @@ -72,7 +76,7 @@ func newService() (auth.Service, string) { } token, _ := t.Issue(key) - return auth.New(krepo, idProvider, t, pEvaluator, pService, loginDuration, refreshDuration, invalidDuration), token + return auth.New(krepo, patsrepo, hasher, idProvider, t, pEvaluator, pService, loginDuration, refreshDuration, invalidDuration), token } func TestIssue(t *testing.T) { diff --git a/auth/tracing/tracing.go b/auth/tracing/tracing.go index 68693987089..06402d0d8eb 100644 --- a/auth/tracing/tracing.go +++ b/auth/tracing/tracing.go @@ -6,8 +6,10 @@ package tracing import ( "context" "fmt" + "time" "github.com/absmach/magistrala/auth" + "github.com/absmach/magistrala/pkg/authn" "github.com/absmach/magistrala/pkg/policies" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -74,3 +76,141 @@ func (tm *tracingMiddleware) Authorize(ctx context.Context, pr policies.Policy) return tm.svc.Authorize(ctx, pr) } + +func (tm *tracingMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope auth.Scope) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "create_pat", trace.WithAttributes( + attribute.String("name", name), + attribute.String("description", description), + attribute.String("duration", duration.String()), + attribute.String("scope", scope.String()), + )) + defer span.End() + return tm.svc.CreatePAT(ctx, session, name, description, duration, scope) +} + +func (tm *tracingMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "update_pat_name", trace.WithAttributes( + attribute.String("pat_id", patID), + attribute.String("name", name), + )) + defer span.End() + return tm.svc.UpdatePATName(ctx, session, patID, name) +} + +func (tm *tracingMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "update_pat_description", trace.WithAttributes( + attribute.String("pat_id", patID), + attribute.String("description", description), + )) + defer span.End() + return tm.svc.UpdatePATDescription(ctx, session, patID, description) +} + +func (tm *tracingMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "retrieve_pat", trace.WithAttributes( + attribute.String("pat_id", patID), + )) + defer span.End() + return tm.svc.RetrievePAT(ctx, session, patID) +} + +func (tm *tracingMiddleware) ListPATS(ctx context.Context, session authn.Session, pm auth.PATSPageMeta) (auth.PATSPage, error) { + ctx, span := tm.tracer.Start(ctx, "list_pat", trace.WithAttributes( + attribute.Int64("limit", int64(pm.Limit)), + attribute.Int64("offset", int64(pm.Offset)), + )) + defer span.End() + return tm.svc.ListPATS(ctx, session, pm) +} + +func (tm *tracingMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) error { + ctx, span := tm.tracer.Start(ctx, "delete_pat", trace.WithAttributes( + attribute.String("pat_id", patID), + )) + defer span.End() + return tm.svc.DeletePAT(ctx, session, patID) +} + +func (tm *tracingMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "reset_pat_secret", trace.WithAttributes( + attribute.String("pat_id", patID), + attribute.String("duration", duration.String()), + )) + defer span.End() + return tm.svc.ResetPATSecret(ctx, session, patID, duration) +} + +func (tm *tracingMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { + ctx, span := tm.tracer.Start(ctx, "revoke_pat_secret", trace.WithAttributes( + attribute.String("pat_id", patID), + )) + defer span.End() + return tm.svc.RevokePATSecret(ctx, session, patID) +} + +func (tm *tracingMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + ctx, span := tm.tracer.Start(ctx, "add_pat_scope_entry", trace.WithAttributes( + attribute.String("pat_id", patID), + attribute.String("platform_entity", platformEntityType.String()), + attribute.String("optional_domain_id", optionalDomainID), + attribute.String("optional_domain_entity", optionalDomainEntityType.String()), + attribute.String("operation", operation.String()), + attribute.StringSlice("entities", entityIDs), + )) + defer span.End() + return tm.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (tm *tracingMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) (auth.Scope, error) { + ctx, span := tm.tracer.Start(ctx, "remove_pat_scope_entry", trace.WithAttributes( + attribute.String("pat_id", patID), + attribute.String("platform_entity", platformEntityType.String()), + attribute.String("optional_domain_id", optionalDomainID), + attribute.String("optional_domain_entity", optionalDomainEntityType.String()), + attribute.String("operation", operation.String()), + attribute.StringSlice("entities", entityIDs), + )) + defer span.End() + return tm.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (tm *tracingMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { + ctx, span := tm.tracer.Start(ctx, "clear_pat_all_scope_entry", trace.WithAttributes( + attribute.String("pat_id", patID), + )) + defer span.End() + return tm.svc.ClearPATAllScopeEntry(ctx, session, patID) +} + +func (tm *tracingMiddleware) IdentifyPAT(ctx context.Context, paToken string) (auth.PAT, error) { + ctx, span := tm.tracer.Start(ctx, "identity_pat") + defer span.End() + return tm.svc.IdentifyPAT(ctx, paToken) +} + +func (tm *tracingMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + ctx, span := tm.tracer.Start(ctx, "authorize_pat", trace.WithAttributes( + attribute.String("personal_access_token", paToken), + attribute.String("platform_entity", platformEntityType.String()), + attribute.String("optional_domain_id", optionalDomainID), + attribute.String("optional_domain_entity", optionalDomainEntityType.String()), + attribute.String("operation", operation.String()), + attribute.StringSlice("entities", entityIDs), + )) + defer span.End() + return tm.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} + +func (tm *tracingMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType auth.PlatformEntityType, optionalDomainID string, optionalDomainEntityType auth.DomainEntityType, operation auth.OperationType, entityIDs ...string) error { + ctx, span := tm.tracer.Start(ctx, "check_pat", trace.WithAttributes( + attribute.String("user_id", userID), + attribute.String("patID", patID), + attribute.String("platform_entity", platformEntityType.String()), + attribute.String("optional_domain_id", optionalDomainID), + attribute.String("optional_domain_entity", optionalDomainEntityType.String()), + attribute.String("operation", operation.String()), + attribute.StringSlice("entities", entityIDs), + )) + defer span.End() + return tm.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) +} diff --git a/pat/events/streams.go b/pat/events/streams.go deleted file mode 100644 index 713ddea5a61..00000000000 --- a/pat/events/streams.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package events - -import ( - "context" - "time" - - "github.com/absmach/magistrala/pat" - "github.com/absmach/magistrala/pkg/authn" - "github.com/absmach/magistrala/pkg/events" - "github.com/absmach/magistrala/pkg/events/store" -) - -const streamID = "magistrala.pat" - -var _ pat.Service = (*eventStore)(nil) - - -type eventStore struct { - events.Publisher - svc pat.Service -} - -// NewEventStoreMiddleware returns wrapper around pat service that sends -// events to event store. -func NewEventStoreMiddleware(ctx context.Context, svc pat.Service, url string) (pat.Service, error) { - publisher, err := store.NewPublisher(ctx, url, streamID) - if err != nil { - return nil, err - } - - return &eventStore{ - svc: svc, - Publisher: publisher, - }, nil -} - -func (es *eventStore) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope pat.Scope) (pat.PAT, error) { - return es.svc.CreatePAT(ctx, session, name, description, duration, scope) -} - -func (es *eventStore) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pat.PAT, error) { - return es.svc.UpdatePATName(ctx, session, patID, name) -} - -func (es *eventStore) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pat.PAT, error) { - return es.svc.UpdatePATDescription(ctx, session, patID, description) -} - -func (es *eventStore) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pat.PAT, error) { - return es.svc.RetrievePAT(ctx, session, patID) -} - -func (es *eventStore) ListPATS(ctx context.Context, session authn.Session, pm pat.PATSPageMeta) (pat.PATSPage, error) { - return es.svc.ListPATS(ctx, session, pm) -} - -func (es *eventStore) DeletePAT(ctx context.Context, session authn.Session, patID string) error { - return es.svc.DeletePAT(ctx, session, patID) -} - -func (es *eventStore) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pat.PAT, error) { - return es.svc.ResetPATSecret(ctx, session, patID, duration) -} - -func (es *eventStore) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { - return es.svc.RevokePATSecret(ctx, session, patID) -} - -func (es *eventStore) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - return es.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (es *eventStore) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - return es.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (es *eventStore) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { - return es.svc.ClearPATAllScopeEntry(ctx, session, patID) -} - -func (es *eventStore) IdentifyPAT(ctx context.Context, paToken string) (pat.PAT, error) { - return es.svc.IdentifyPAT(ctx, paToken) -} - -func (es *eventStore) AuthorizePAT(ctx context.Context, paToken string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - return es.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (es *eventStore) CheckPAT(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - return es.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} \ No newline at end of file diff --git a/pat/middleware/authorization.go b/pat/middleware/authorization.go deleted file mode 100644 index 10645900881..00000000000 --- a/pat/middleware/authorization.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package middleware - -import ( - "context" - "time" - - "github.com/absmach/magistrala/pat" - "github.com/absmach/magistrala/pkg/authn" - mgauthz "github.com/absmach/magistrala/pkg/authz" -) - -var _ pat.Service = (*authorizationMiddleware)(nil) - -type authorizationMiddleware struct { - svc pat.Service - authz mgauthz.Authorization -} - -// AuthorizationMiddleware adds authorization to the clients service. -func AuthorizationMiddleware(entityType string, svc pat.Service, authz mgauthz.Authorization) (pat.Service, error) { - return &authorizationMiddleware{ - svc: svc, - authz: authz, - }, nil -} - -func (am *authorizationMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope pat.Scope) (pat.PAT, error) { - return am.svc.CreatePAT(ctx, session, name, description, duration, scope) -} - -func (am *authorizationMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pat.PAT, error) { - return am.svc.UpdatePATName(ctx, session, patID, name) -} - -func (am *authorizationMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pat.PAT, error) { - return am.svc.UpdatePATDescription(ctx, session, patID, description) -} - -func (am *authorizationMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pat.PAT, error) { - return am.svc.RetrievePAT(ctx, session, patID) -} - -func (am *authorizationMiddleware) ListPATS(ctx context.Context, session authn.Session, pm pat.PATSPageMeta) (pat.PATSPage, error) { - return am.svc.ListPATS(ctx, session, pm) -} - -func (am *authorizationMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) error { - return am.svc.DeletePAT(ctx, session, patID) -} - -func (am *authorizationMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pat.PAT, error) { - return am.svc.ResetPATSecret(ctx, session, patID, duration) -} - -func (am *authorizationMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { - return am.svc.RevokePATSecret(ctx, session, patID) -} - -func (am *authorizationMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - return am.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (am *authorizationMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - return am.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (am *authorizationMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { - return am.svc.ClearPATAllScopeEntry(ctx, session, patID) -} - -func (am *authorizationMiddleware) IdentifyPAT(ctx context.Context, secret string) (pat.PAT, error) { - return am.svc.IdentifyPAT(ctx, secret) -} - -func (am *authorizationMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - return am.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (am *authorizationMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - return am.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} diff --git a/pat/middleware/logging.go b/pat/middleware/logging.go deleted file mode 100644 index 51767d39c1b..00000000000 --- a/pat/middleware/logging.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package middleware - -import ( - "context" - "log/slog" - "time" - - "github.com/absmach/magistrala/pat" - "github.com/absmach/magistrala/pkg/authn" -) - -var _ pat.Service = (*loggingMiddleware)(nil) - -type loggingMiddleware struct { - logger *slog.Logger - svc pat.Service -} - -// LoggingMiddleware adds logging facilities to the core service. -func LoggingMiddleware(svc pat.Service, logger *slog.Logger) pat.Service { - return &loggingMiddleware{logger, svc} -} - -func (lm *loggingMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope pat.Scope) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("name", name), - slog.String("description", description), - slog.String("pat_duration", duration.String()), - slog.String("scope", scope.String()), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Create PAT failed to complete successfully", args...) - return - } - lm.logger.Info("Create PAT completed successfully", args...) - }(time.Now()) - return lm.svc.CreatePAT(ctx, session, name, description, duration, scope) -} - -func (lm *loggingMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - slog.String("name", name), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Update PAT name failed to complete successfully", args...) - return - } - lm.logger.Info("Update PAT name completed successfully", args...) - }(time.Now()) - return lm.svc.UpdatePATName(ctx, session, patID, name) -} - -func (lm *loggingMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - slog.String("description", description), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Update PAT description failed to complete successfully", args...) - return - } - lm.logger.Info("Update PAT description completed successfully", args...) - }(time.Now()) - return lm.svc.UpdatePATDescription(ctx, session, patID, description) -} - -func (lm *loggingMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Retrieve PAT failed to complete successfully", args...) - return - } - lm.logger.Info("Retrieve PAT completed successfully", args...) - }(time.Now()) - return lm.svc.RetrievePAT(ctx, session, patID) -} - -func (lm *loggingMiddleware) ListPATS(ctx context.Context, session authn.Session, pm pat.PATSPageMeta) (pp pat.PATSPage, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.Uint64("limit", pm.Limit), - slog.Uint64("offset", pm.Offset), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("List PATS failed to complete successfully", args...) - return - } - lm.logger.Info("List PATS completed successfully", args...) - }(time.Now()) - return lm.svc.ListPATS(ctx, session, pm) -} - -func (lm *loggingMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) (err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Delete PAT failed to complete successfully", args...) - return - } - lm.logger.Info("Delete PAT completed successfully", args...) - }(time.Now()) - return lm.svc.DeletePAT(ctx, session, patID) -} - -func (lm *loggingMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - slog.String("pat_duration", duration.String()), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Reset PAT secret failed to complete successfully", args...) - return - } - lm.logger.Info("Reset PAT secret completed successfully", args...) - }(time.Now()) - return lm.svc.ResetPATSecret(ctx, session, patID, duration) -} - -func (lm *loggingMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) (err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Revoke PAT secret failed to complete successfully", args...) - return - } - lm.logger.Info("Revoke PAT secret completed successfully", args...) - }(time.Now()) - return lm.svc.RevokePATSecret(ctx, session, patID) -} - -func (lm *loggingMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (sc pat.Scope, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - slog.String("platform_entity_type", platformEntityType.String()), - slog.String("optional_domain_id", optionalDomainID), - slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), - slog.String("operation", operation.String()), - slog.Any("entities", entityIDs), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Add entry to PAT scope failed to complete successfully", args...) - return - } - lm.logger.Info("Add entry to PAT scope completed successfully", args...) - }(time.Now()) - return lm.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (lm *loggingMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (sc pat.Scope, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - slog.String("platform_entity_type", platformEntityType.String()), - slog.String("optional_domain_id", optionalDomainID), - slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), - slog.String("operation", operation.String()), - slog.Any("entities", entityIDs), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Remove entry from PAT scope failed to complete successfully", args...) - return - } - lm.logger.Info("Remove entry from PAT scope completed successfully", args...) - }(time.Now()) - return lm.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (lm *loggingMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) (err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("pat_id", patID), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Clear all entry from PAT scope failed to complete successfully", args...) - return - } - lm.logger.Info("Clear all entry from PAT scope completed successfully", args...) - }(time.Now()) - return lm.svc.ClearPATAllScopeEntry(ctx, session, patID) -} - -func (lm *loggingMiddleware) IdentifyPAT(ctx context.Context, paToken string) (pa pat.PAT, err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Identify PAT failed to complete successfully", args...) - return - } - lm.logger.Info("Identify PAT completed successfully", args...) - }(time.Now()) - return lm.svc.IdentifyPAT(ctx, paToken) -} - -func (lm *loggingMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("platform_entity_type", platformEntityType.String()), - slog.String("optional_domain_id", optionalDomainID), - slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), - slog.String("operation", operation.String()), - slog.Any("entities", entityIDs), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Authorize PAT failed complete successfully", args...) - return - } - lm.logger.Info("Authorize PAT completed successfully", args...) - }(time.Now()) - return lm.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (lm *loggingMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (err error) { - defer func(begin time.Time) { - args := []any{ - slog.String("duration", time.Since(begin).String()), - slog.String("user_id", userID), - slog.String("pat_id", patID), - slog.String("platform_entity_type", platformEntityType.String()), - slog.String("optional_domain_id", optionalDomainID), - slog.String("optional_domain_entity_type", optionalDomainEntityType.String()), - slog.String("operation", operation.String()), - slog.Any("entities", entityIDs), - } - if err != nil { - args = append(args, slog.Any("error", err)) - lm.logger.Warn("Check PAT failed complete successfully", args...) - return - } - lm.logger.Info("Check PAT completed successfully", args...) - }(time.Now()) - return lm.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} diff --git a/pat/middleware/metrics.go b/pat/middleware/metrics.go deleted file mode 100644 index 4a44bb0aa15..00000000000 --- a/pat/middleware/metrics.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package middleware - -import ( - "context" - "time" - - "github.com/absmach/magistrala/pat" - "github.com/absmach/magistrala/pkg/authn" - "github.com/go-kit/kit/metrics" -) - -var _ pat.Service = (*metricsMiddleware)(nil) - -type metricsMiddleware struct { - counter metrics.Counter - latency metrics.Histogram - svc pat.Service -} - -// MetricsMiddleware instruments core service by tracking request count and latency. -func MetricsMiddleware(svc pat.Service, counter metrics.Counter, latency metrics.Histogram) pat.Service { - return &metricsMiddleware{ - counter: counter, - latency: latency, - svc: svc, - } -} - -func (ms *metricsMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope pat.Scope) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "create_pat").Add(1) - ms.latency.With("method", "create_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.CreatePAT(ctx, session, name, description, duration, scope) -} - -func (ms *metricsMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "update_pat_name").Add(1) - ms.latency.With("method", "update_pat_name").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.UpdatePATName(ctx, session, patID, name) -} - -func (ms *metricsMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "update_pat_description").Add(1) - ms.latency.With("method", "update_pat_description").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.UpdatePATDescription(ctx, session, patID, description) -} - -func (ms *metricsMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "retrieve_pat").Add(1) - ms.latency.With("method", "retrieve_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.RetrievePAT(ctx, session, patID) -} - -func (ms *metricsMiddleware) ListPATS(ctx context.Context, session authn.Session, pm pat.PATSPageMeta) (pat.PATSPage, error) { - defer func(begin time.Time) { - ms.counter.With("method", "list_pats").Add(1) - ms.latency.With("method", "list_pats").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.ListPATS(ctx, session, pm) -} - -func (ms *metricsMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) error { - defer func(begin time.Time) { - ms.counter.With("method", "delete_pat").Add(1) - ms.latency.With("method", "delete_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.DeletePAT(ctx, session, patID) -} - -func (ms *metricsMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "reset_pat_secret").Add(1) - ms.latency.With("method", "reset_pat_secret").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.ResetPATSecret(ctx, session, patID, duration) -} - -func (ms *metricsMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { - defer func(begin time.Time) { - ms.counter.With("method", "revoke_pat_secret").Add(1) - ms.latency.With("method", "revoke_pat_secret").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.RevokePATSecret(ctx, session, patID) -} - -func (ms *metricsMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - defer func(begin time.Time) { - ms.counter.With("method", "add_pat_scope_entry").Add(1) - ms.latency.With("method", "add_pat_scope_entry").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (ms *metricsMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - defer func(begin time.Time) { - ms.counter.With("method", "remove_pat_scope_entry").Add(1) - ms.latency.With("method", "remove_pat_scope_entry").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (ms *metricsMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { - defer func(begin time.Time) { - ms.counter.With("method", "clear_pat_all_scope_entry").Add(1) - ms.latency.With("method", "clear_pat_all_scope_entry").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.ClearPATAllScopeEntry(ctx, session, patID) -} - -func (ms *metricsMiddleware) IdentifyPAT(ctx context.Context, paToken string) (pat.PAT, error) { - defer func(begin time.Time) { - ms.counter.With("method", "identify_pat").Add(1) - ms.latency.With("method", "identify_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.IdentifyPAT(ctx, paToken) -} - -func (ms *metricsMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - defer func(begin time.Time) { - ms.counter.With("method", "authorize_pat").Add(1) - ms.latency.With("method", "authorize_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (ms *metricsMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - defer func(begin time.Time) { - ms.counter.With("method", "check_pat").Add(1) - ms.latency.With("method", "check_pat").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} diff --git a/pat/service.go b/pat/service.go deleted file mode 100644 index 9c995914e40..00000000000 --- a/pat/service.go +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package pat - -import ( - "context" - "encoding/base64" - "math/rand" - "strings" - "time" - - "github.com/absmach/magistrala" - "github.com/absmach/magistrala/pkg/authn" - "github.com/absmach/magistrala/pkg/errors" - svcerr "github.com/absmach/magistrala/pkg/errors/service" - "github.com/google/uuid" -) - -const ( - randStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&&*|+-=" - patPrefix = "pat" - patSecretSeparator = "_" -) - -var ( - errMalformedPAT = errors.New("malformed personal access token") - errFailedToParseUUID = errors.New("failed to parse string to UUID") - errInvalidLenFor2UUIDs = errors.New("invalid input length for 2 UUID, excepted 32 byte") - errRevokedPAT = errors.New("revoked pat") - errCreatePAT = errors.New("failed to create PAT") - errUpdatePAT = errors.New("failed to update PAT") - errRetrievePAT = errors.New("failed to retrieve PAT") - errDeletePAT = errors.New("failed to delete PAT") - errRevokePAT = errors.New("failed to revoke PAT") - errClearAllScope = errors.New("failed to clear all entry in scope") -) - -type service struct { - pats PATSRepository - hasher Hasher - idProvider magistrala.IDProvider -} - -var _ Service = (*service)(nil) - -// New instantiates the auth service implementation. -func New(pats PATSRepository, hasher Hasher, idp magistrala.IDProvider) Service { - return &service{ - pats: pats, - hasher: hasher, - idProvider: idp, - } -} - -func (svc service) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope Scope) (PAT, error) { - id, err := svc.idProvider.ID() - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrCreateEntity, err) - } - secret, hash, err := svc.generateSecretAndHash(session.UserID, id) - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrCreateEntity, err) - } - - now := time.Now() - pat := PAT{ - ID: id, - User: session.UserID, - Name: name, - Description: description, - Secret: hash, - IssuedAt: now, - ExpiresAt: now.Add(duration), - Scope: scope, - } - if err := svc.pats.Save(ctx, pat); err != nil { - return PAT{}, errors.Wrap(errCreatePAT, err) - } - pat.Secret = secret - return pat, nil -} - -func (svc service) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (PAT, error) { - pat, err := svc.pats.UpdateName(ctx, session.UserID, patID, name) - if err != nil { - return PAT{}, errors.Wrap(errUpdatePAT, err) - } - return pat, nil -} - -func (svc service) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (PAT, error) { - pat, err := svc.pats.UpdateDescription(ctx, session.UserID, patID, description) - if err != nil { - return PAT{}, errors.Wrap(errUpdatePAT, err) - } - return pat, nil -} - -func (svc service) RetrievePAT(ctx context.Context, session authn.Session, patID string) (PAT, error) { - pat, err := svc.pats.Retrieve(ctx, session.UserID, patID) - if err != nil { - return PAT{}, errors.Wrap(errRetrievePAT, err) - } - return pat, nil -} - -func (svc service) ListPATS(ctx context.Context, session authn.Session, pm PATSPageMeta) (PATSPage, error) { - patsPage, err := svc.pats.RetrieveAll(ctx, session.UserID, pm) - if err != nil { - return PATSPage{}, errors.Wrap(errRetrievePAT, err) - } - return patsPage, nil -} - -func (svc service) DeletePAT(ctx context.Context, session authn.Session, patID string) error { - if err := svc.pats.Remove(ctx, session.UserID, patID); err != nil { - return errors.Wrap(errDeletePAT, err) - } - return nil -} - -func (svc service) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (PAT, error) { - // Generate new HashToken take place here - secret, hash, err := svc.generateSecretAndHash(session.UserID, patID) - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) - } - - pat, err := svc.pats.UpdateTokenHash(ctx, session.UserID, patID, hash, time.Now().Add(duration)) - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) - } - - if err := svc.pats.Reactivate(ctx, session.UserID, patID); err != nil { - return PAT{}, errors.Wrap(svcerr.ErrUpdateEntity, err) - } - pat.Secret = secret - pat.Revoked = false - pat.RevokedAt = time.Time{} - return pat, nil -} - -func (svc service) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { - if err := svc.pats.Revoke(ctx, session.UserID, patID); err != nil { - return errors.Wrap(errRevokePAT, err) - } - return nil -} - -func (svc service) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) (Scope, error) { - scope, err := svc.pats.AddScopeEntry(ctx, session.UserID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) - if err != nil { - return Scope{}, errors.Wrap(errRevokePAT, err) - } - return scope, nil -} - -func (svc service) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) (Scope, error) { - scope, err := svc.pats.RemoveScopeEntry(ctx, session.UserID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) - if err != nil { - return Scope{}, err - } - return scope, nil -} - -func (svc service) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { - if err := svc.pats.RemoveAllScopeEntry(ctx, session.UserID, patID); err != nil { - return errors.Wrap(errClearAllScope, err) - } - return nil -} - -func (svc service) IdentifyPAT(ctx context.Context, secret string) (PAT, error) { - parts := strings.Split(secret, patSecretSeparator) - if len(parts) != 3 && parts[0] != patPrefix { - return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errMalformedPAT) - } - userID, patID, err := decode(parts[1]) - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errMalformedPAT) - } - secretHash, revoked, err := svc.pats.RetrieveSecretAndRevokeStatus(ctx, userID.String(), patID.String()) - if err != nil { - return PAT{}, errors.Wrap(svcerr.ErrAuthentication, err) - } - if revoked { - return PAT{}, errors.Wrap(svcerr.ErrAuthentication, errRevokedPAT) - } - if err := svc.hasher.Compare(secret, secretHash); err != nil { - return PAT{}, errors.Wrap(svcerr.ErrAuthentication, err) - } - return PAT{ID: patID.String(), User: userID.String()}, nil -} - -func (svc service) AuthorizePAT(ctx context.Context, paToken string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) error { - res, err := svc.IdentifyPAT(ctx, paToken) - if err != nil { - return err - } - if err := svc.pats.CheckScopeEntry(ctx, res.User, res.ID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...); err != nil { - return errors.Wrap(svcerr.ErrAuthorization, err) - } - return nil -} - -func (svc service) CheckPAT(ctx context.Context, userID, patID string, platformEntityType PlatformEntityType, optionalDomainID string, optionalDomainEntityType DomainEntityType, operation OperationType, entityIDs ...string) error { - if err := svc.pats.CheckScopeEntry(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...); err != nil { - return errors.Wrap(svcerr.ErrAuthorization, err) - } - return nil -} - -func (svc service) generateSecretAndHash(userID, patID string) (string, string, error) { - uID, err := uuid.Parse(userID) - if err != nil { - return "", "", errors.Wrap(errFailedToParseUUID, err) - } - pID, err := uuid.Parse(patID) - if err != nil { - return "", "", errors.Wrap(errFailedToParseUUID, err) - } - - secret := patPrefix + patSecretSeparator + encode(uID, pID) + patSecretSeparator + generateRandomString(100) - secretHash, err := svc.hasher.Hash(secret) - return secret, secretHash, err -} - -func encode(userID, patID uuid.UUID) string { - c := append(userID[:], patID[:]...) - return base64.StdEncoding.EncodeToString(c) -} - -func decode(encoded string) (uuid.UUID, uuid.UUID, error) { - data, err := base64.StdEncoding.DecodeString(encoded) - if err != nil { - return uuid.Nil, uuid.Nil, err - } - - if len(data) != 32 { - return uuid.Nil, uuid.Nil, errInvalidLenFor2UUIDs - } - - var userID, patID uuid.UUID - copy(userID[:], data[:16]) - copy(patID[:], data[16:]) - - return userID, patID, nil -} - -func generateRandomString(n int) string { - letterRunes := []rune(randStr) - rand.New(rand.NewSource(time.Now().UnixNano())) - b := make([]rune, n) - for i := range b { - b[i] = letterRunes[rand.Intn(len(letterRunes))] - } - return string(b) -} diff --git a/pat/tracing/tracing.go b/pat/tracing/tracing.go deleted file mode 100644 index 4fab5fae492..00000000000 --- a/pat/tracing/tracing.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package tracing - -import ( - "context" - "time" - - "github.com/absmach/magistrala/pat" - "github.com/absmach/magistrala/pkg/authn" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" -) - -var _ pat.Service = (*tracingMiddleware)(nil) - -type tracingMiddleware struct { - tracer trace.Tracer - svc pat.Service -} - -// New returns a new group service with tracing capabilities. -func New(svc pat.Service, tracer trace.Tracer) pat.Service { - return &tracingMiddleware{tracer, svc} -} - -func (tm *tracingMiddleware) CreatePAT(ctx context.Context, session authn.Session, name, description string, duration time.Duration, scope pat.Scope) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "create_pat", trace.WithAttributes( - attribute.String("name", name), - attribute.String("description", description), - attribute.String("duration", duration.String()), - attribute.String("scope", scope.String()), - )) - defer span.End() - return tm.svc.CreatePAT(ctx, session, name, description, duration, scope) -} - -func (tm *tracingMiddleware) UpdatePATName(ctx context.Context, session authn.Session, patID, name string) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "update_pat_name", trace.WithAttributes( - attribute.String("pat_id", patID), - attribute.String("name", name), - )) - defer span.End() - return tm.svc.UpdatePATName(ctx, session, patID, name) -} - -func (tm *tracingMiddleware) UpdatePATDescription(ctx context.Context, session authn.Session, patID, description string) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "update_pat_description", trace.WithAttributes( - attribute.String("pat_id", patID), - attribute.String("description", description), - )) - defer span.End() - return tm.svc.UpdatePATDescription(ctx, session, patID, description) -} - -func (tm *tracingMiddleware) RetrievePAT(ctx context.Context, session authn.Session, patID string) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "retrieve_pat", trace.WithAttributes( - attribute.String("pat_id", patID), - )) - defer span.End() - return tm.svc.RetrievePAT(ctx, session, patID) -} - -func (tm *tracingMiddleware) ListPATS(ctx context.Context, session authn.Session, pm pat.PATSPageMeta) (pat.PATSPage, error) { - ctx, span := tm.tracer.Start(ctx, "list_pat", trace.WithAttributes( - attribute.Int64("limit", int64(pm.Limit)), - attribute.Int64("offset", int64(pm.Offset)), - )) - defer span.End() - return tm.svc.ListPATS(ctx, session, pm) -} - -func (tm *tracingMiddleware) DeletePAT(ctx context.Context, session authn.Session, patID string) error { - ctx, span := tm.tracer.Start(ctx, "delete_pat", trace.WithAttributes( - attribute.String("pat_id", patID), - )) - defer span.End() - return tm.svc.DeletePAT(ctx, session, patID) -} - -func (tm *tracingMiddleware) ResetPATSecret(ctx context.Context, session authn.Session, patID string, duration time.Duration) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "reset_pat_secret", trace.WithAttributes( - attribute.String("pat_id", patID), - attribute.String("duration", duration.String()), - )) - defer span.End() - return tm.svc.ResetPATSecret(ctx, session, patID, duration) -} - -func (tm *tracingMiddleware) RevokePATSecret(ctx context.Context, session authn.Session, patID string) error { - ctx, span := tm.tracer.Start(ctx, "revoke_pat_secret", trace.WithAttributes( - attribute.String("pat_id", patID), - )) - defer span.End() - return tm.svc.RevokePATSecret(ctx, session, patID) -} - -func (tm *tracingMiddleware) AddPATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - ctx, span := tm.tracer.Start(ctx, "add_pat_scope_entry", trace.WithAttributes( - attribute.String("pat_id", patID), - attribute.String("platform_entity", platformEntityType.String()), - attribute.String("optional_domain_id", optionalDomainID), - attribute.String("optional_domain_entity", optionalDomainEntityType.String()), - attribute.String("operation", operation.String()), - attribute.StringSlice("entities", entityIDs), - )) - defer span.End() - return tm.svc.AddPATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (tm *tracingMiddleware) RemovePATScopeEntry(ctx context.Context, session authn.Session, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) (pat.Scope, error) { - ctx, span := tm.tracer.Start(ctx, "remove_pat_scope_entry", trace.WithAttributes( - attribute.String("pat_id", patID), - attribute.String("platform_entity", platformEntityType.String()), - attribute.String("optional_domain_id", optionalDomainID), - attribute.String("optional_domain_entity", optionalDomainEntityType.String()), - attribute.String("operation", operation.String()), - attribute.StringSlice("entities", entityIDs), - )) - defer span.End() - return tm.svc.RemovePATScopeEntry(ctx, session, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (tm *tracingMiddleware) ClearPATAllScopeEntry(ctx context.Context, session authn.Session, patID string) error { - ctx, span := tm.tracer.Start(ctx, "clear_pat_all_scope_entry", trace.WithAttributes( - attribute.String("pat_id", patID), - )) - defer span.End() - return tm.svc.ClearPATAllScopeEntry(ctx, session, patID) -} - -func (tm *tracingMiddleware) IdentifyPAT(ctx context.Context, paToken string) (pat.PAT, error) { - ctx, span := tm.tracer.Start(ctx, "identity_pat") - defer span.End() - return tm.svc.IdentifyPAT(ctx, paToken) -} - -func (tm *tracingMiddleware) AuthorizePAT(ctx context.Context, paToken string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - ctx, span := tm.tracer.Start(ctx, "authorize_pat", trace.WithAttributes( - attribute.String("personal_access_token", paToken), - attribute.String("platform_entity", platformEntityType.String()), - attribute.String("optional_domain_id", optionalDomainID), - attribute.String("optional_domain_entity", optionalDomainEntityType.String()), - attribute.String("operation", operation.String()), - attribute.StringSlice("entities", entityIDs), - )) - defer span.End() - return tm.svc.AuthorizePAT(ctx, paToken, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -} - -func (tm *tracingMiddleware) CheckPAT(ctx context.Context, userID, patID string, platformEntityType pat.PlatformEntityType, optionalDomainID string, optionalDomainEntityType pat.DomainEntityType, operation pat.OperationType, entityIDs ...string) error { - ctx, span := tm.tracer.Start(ctx, "check_pat", trace.WithAttributes( - attribute.String("user_id", userID), - attribute.String("patID", patID), - attribute.String("platform_entity", platformEntityType.String()), - attribute.String("optional_domain_id", optionalDomainID), - attribute.String("optional_domain_entity", optionalDomainEntityType.String()), - attribute.String("operation", operation.String()), - attribute.StringSlice("entities", entityIDs), - )) - defer span.End() - return tm.svc.CheckPAT(ctx, userID, patID, platformEntityType, optionalDomainID, optionalDomainEntityType, operation, entityIDs...) -}