Support run-as for automation scripts
Add grpc-server capabilities for system service (make jwt, find user by id) Add jwt generation (via grpc) to compose for run-as automation-scripts Add SuperUser for system-level tasks and operations that are ran in the background w/o initiator and require permision checking
This commit is contained in:
@@ -170,6 +170,12 @@ function proto {
|
||||
module.proto \
|
||||
record.proto \
|
||||
script_runner.proto
|
||||
|
||||
yellow " ${CORTEZA_PROTOBUF_PATH} >> system/proto"
|
||||
PATH=$PATH:$GOPATH/bin protoc \
|
||||
--proto_path ${CORTEZA_PROTOBUF_PATH}/system \
|
||||
--go_out=plugins=grpc:system/proto \
|
||||
user.proto
|
||||
green "OK"
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,9 @@ func Configure() *cli.Config {
|
||||
servicesInitialized = true
|
||||
|
||||
cli.HandleError(service.Init(ctx, c.Log, service.Config{
|
||||
Storage: *c.StorageOpt,
|
||||
ScriptRunner: *c.ScriptRunner,
|
||||
Storage: *c.StorageOpt,
|
||||
ScriptRunner: *c.ScriptRunner,
|
||||
GRPCClientSystem: *c.GRPCServerSystem,
|
||||
}))
|
||||
},
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ func (svc automationRunner) makeRecordScriptRunner(ctx context.Context, ns *type
|
||||
defer cancelFn()
|
||||
|
||||
// Add invoker's or defined credentials/jwt
|
||||
req.JWT = svc.getJWT(ctx, script.RunAs)
|
||||
req.JWT = svc.getJWT(ctx, script)
|
||||
|
||||
// Add script info
|
||||
req.Script = proto.FromAutomationScript(script)
|
||||
@@ -295,10 +295,9 @@ func (svc automationRunner) makeRecordScriptRunner(ctx context.Context, ns *type
|
||||
}
|
||||
}
|
||||
|
||||
// Who modified/created/owns the Record
|
||||
var currentUserID = auth.GetIdentityFromContext(ctx).Identity()
|
||||
if script.RunAs > 0 {
|
||||
currentUserID = script.RunAs
|
||||
}
|
||||
currentUserID = script.RunAs
|
||||
|
||||
if r.OwnedBy == 0 {
|
||||
r.OwnedBy = currentUserID
|
||||
@@ -317,11 +316,12 @@ func (svc automationRunner) makeRecordScriptRunner(ctx context.Context, ns *type
|
||||
}
|
||||
|
||||
// Creates a new JWT for
|
||||
func (svc automationRunner) getJWT(ctx context.Context, userID uint64) string {
|
||||
if userID > 0 {
|
||||
func (svc automationRunner) getJWT(ctx context.Context, script *automation.Script) string {
|
||||
if script.RunAsDefined() {
|
||||
// @todo implement this
|
||||
// at the moment we do not he the ability fetch user info from non-system service
|
||||
// extend/implement this feature when our services will know how to communicate with each-other
|
||||
return script.Credentials()
|
||||
}
|
||||
|
||||
return svc.jwtEncoder.Encode(auth.GetIdentityFromContext(ctx))
|
||||
|
||||
@@ -8,10 +8,12 @@ import (
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/proto"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/store"
|
||||
"github.com/cortezaproject/corteza-server/pkg/automation"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/options"
|
||||
proto2 "github.com/cortezaproject/corteza-server/system/proto"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -20,16 +22,10 @@ type (
|
||||
Watch(ctx context.Context)
|
||||
}
|
||||
|
||||
// automationManager interface {
|
||||
// automationScriptsFinder
|
||||
// automationScriptManager
|
||||
// automationTriggerManager
|
||||
// Watch(ctx context.Context)
|
||||
// }
|
||||
|
||||
Config struct {
|
||||
Storage options.StorageOpt
|
||||
ScriptRunner options.ScriptRunnerOpt
|
||||
Storage options.StorageOpt
|
||||
ScriptRunner options.ScriptRunnerOpt
|
||||
GRPCClientSystem options.GRPCServerOpt
|
||||
}
|
||||
)
|
||||
|
||||
@@ -59,6 +55,8 @@ var (
|
||||
|
||||
DefaultAttachment AttachmentService
|
||||
DefaultNotification NotificationService
|
||||
|
||||
DefaultSystemUser *systemUser
|
||||
)
|
||||
|
||||
func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
@@ -80,12 +78,25 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
|
||||
DefaultAccessControl = AccessControl(DefaultPermissions)
|
||||
|
||||
// ias Internal Automatinon Service
|
||||
{
|
||||
systemClientConn, err := NewSystemGRPCClient(ctx, c.GRPCClientSystem, DefaultLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
DefaultSystemUser = SystemUser(proto2.NewUsersClient(systemClientConn))
|
||||
}
|
||||
|
||||
// ias: Internal Automatinon Service
|
||||
// handles script & trigger management & keeping runnables cripts in internal cache
|
||||
ias := automation.Service(automation.AutomationServiceConfig{
|
||||
Logger: DefaultLogger,
|
||||
DbTablePrefix: "compose",
|
||||
DB: db,
|
||||
TokenMaker: func(ctx context.Context, userID uint64) (s string, e error) {
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
return DefaultSystemUser.MakeJWT(ctx, userID)
|
||||
},
|
||||
})
|
||||
|
||||
// Pass automation manager to
|
||||
|
||||
33
compose/internal/service/system_grpc_client.go
Normal file
33
compose/internal/service/system_grpc_client.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/options"
|
||||
)
|
||||
|
||||
// Connects to system gRPC server
|
||||
func NewSystemGRPCClient(ctx context.Context, opt options.GRPCServerOpt, logger *zap.Logger) (c *grpc.ClientConn, err error) {
|
||||
if opt.ClientLog {
|
||||
// Send logs to zap
|
||||
//
|
||||
// waiting for https://github.com/uber-go/zap/pull/538
|
||||
grpclog.SetLogger(zapgrpc.NewLogger(logger.Named("grpc-client-system")))
|
||||
}
|
||||
|
||||
var dopts = []grpc.DialOption{
|
||||
// @todo insecure?
|
||||
grpc.WithInsecure(),
|
||||
}
|
||||
|
||||
if opt.ClientMaxBackoffDelay > 0 {
|
||||
dopts = append(dopts, grpc.WithBackoffMaxDelay(opt.ClientMaxBackoffDelay))
|
||||
}
|
||||
|
||||
return grpc.DialContext(ctx, opt.Addr, dopts...)
|
||||
}
|
||||
54
compose/internal/service/system_user.go
Normal file
54
compose/internal/service/system_user.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/proto"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
// gRPC client for
|
||||
|
||||
type (
|
||||
systemUser struct {
|
||||
client proto.UsersClient
|
||||
}
|
||||
)
|
||||
|
||||
func SystemUser(c proto.UsersClient) *systemUser {
|
||||
return &systemUser{
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc systemUser) MakeJWT(ctx context.Context, ID uint64) (string, error) {
|
||||
ctx = metadata.NewOutgoingContext(ctx, metadata.MD{
|
||||
"jwt": []string{auth.GetJwtFromContext(ctx)},
|
||||
})
|
||||
|
||||
rsp, err := svc.client.MakeJWT(ctx, &proto.MakeJWTRequest{UserID: ID}, grpc.WaitForReady(true))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return rsp.JWT, nil
|
||||
}
|
||||
|
||||
func (svc systemUser) FindByID(ctx context.Context, ID uint64) (*types.User, error) {
|
||||
rsp, err := svc.client.FindByID(ctx, &proto.FindByIDRequest{UserID: ID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.User{
|
||||
ID: rsp.User.ID,
|
||||
Email: rsp.User.Email,
|
||||
Name: rsp.User.Name,
|
||||
Handle: rsp.User.Handle,
|
||||
Kind: types.UserKind(rsp.User.Kind),
|
||||
}, nil
|
||||
}
|
||||
@@ -313,6 +313,10 @@ func (ctrl AutomationScript) makePayload(ctx context.Context, s *automation.Scri
|
||||
CanGrant: ctrl.ac.CanGrant(ctx),
|
||||
CanUpdate: ctrl.ac.CanUpdateAutomationScript(ctx, s),
|
||||
CanDelete: ctrl.ac.CanDeleteAutomationScript(ctx, s),
|
||||
|
||||
CanSetRunner: ctrl.ac.CanGrant(ctx),
|
||||
CanSetAsCritical: true,
|
||||
CanSetAsAsync: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
superUserID uint64 = 10000000000000000
|
||||
)
|
||||
|
||||
func NewIdentity(id uint64, rr ...uint64) *Identity {
|
||||
return &Identity{
|
||||
id: id,
|
||||
@@ -25,3 +29,11 @@ func (i Identity) Roles() []uint64 {
|
||||
func (i Identity) Valid() bool {
|
||||
return i.id > 0
|
||||
}
|
||||
|
||||
func NewSuperUserIdentity() *Identity {
|
||||
return NewIdentity(superUserID)
|
||||
}
|
||||
|
||||
func IsSuperUser(i Identifiable) bool {
|
||||
return superUserID == i.Identity()
|
||||
}
|
||||
|
||||
@@ -5,21 +5,42 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ctxKey int
|
||||
)
|
||||
|
||||
var (
|
||||
identityCtxKey ctxKey
|
||||
identityCtxKey struct{}
|
||||
jwtCtxKey struct{}
|
||||
)
|
||||
|
||||
func SetIdentityToContext(ctx context.Context, identity Identifiable) context.Context {
|
||||
return context.WithValue(ctx, identityCtxKey, identity)
|
||||
return context.WithValue(ctx, identityCtxKey{}, identity)
|
||||
}
|
||||
|
||||
func GetIdentityFromContext(ctx context.Context) Identifiable {
|
||||
if identity, ok := ctx.Value(identityCtxKey).(Identifiable); ok {
|
||||
if identity, ok := ctx.Value(identityCtxKey{}).(Identifiable); ok {
|
||||
return identity
|
||||
} else {
|
||||
return NewIdentity(0)
|
||||
}
|
||||
}
|
||||
|
||||
func SetJwtToContext(ctx context.Context, jwt string) context.Context {
|
||||
return context.WithValue(ctx, jwtCtxKey{}, jwt)
|
||||
|
||||
}
|
||||
|
||||
func GetJwtFromContext(ctx context.Context) string {
|
||||
if jwt, ok := ctx.Value(jwtCtxKey{}).(string); ok {
|
||||
return jwt
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// SetSuperUserContext stores system user as identity
|
||||
// and accompanying JWT for it to the context
|
||||
func SetSuperUserContext(ctx context.Context) context.Context {
|
||||
su := NewSuperUserIdentity()
|
||||
|
||||
ctx = SetIdentityToContext(ctx, su)
|
||||
ctx = SetJwtToContext(ctx, DefaultJwtHandler.Encode(su))
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -15,10 +15,16 @@ type (
|
||||
Encode(identity Identifiable) string
|
||||
}
|
||||
|
||||
TokenDecoder interface {
|
||||
Decode(token string) (Identifiable, error)
|
||||
}
|
||||
|
||||
TokenHandler interface {
|
||||
Encode(identity Identifiable) string
|
||||
Verifier() func(http.Handler) http.Handler
|
||||
Authenticator() func(http.Handler) http.Handler
|
||||
TokenEncoder
|
||||
TokenDecoder
|
||||
|
||||
HttpVerifier() func(http.Handler) http.Handler
|
||||
HttpAuthenticator() func(http.Handler) http.Handler
|
||||
}
|
||||
|
||||
Signer interface {
|
||||
|
||||
@@ -44,10 +44,45 @@ func JWT(secret string, expiry int64) (jwt *token, err error) {
|
||||
}
|
||||
|
||||
// Verifies JWT and stores it into context
|
||||
func (t *token) Verifier() func(http.Handler) http.Handler {
|
||||
func (t *token) HttpVerifier() func(http.Handler) http.Handler {
|
||||
return jwtauth.Verifier(t.tokenAuth)
|
||||
}
|
||||
|
||||
func (t *token) Decode(ts string) (Identifiable, error) {
|
||||
var (
|
||||
decoded, err = t.tokenAuth.Decode(ts)
|
||||
|
||||
rr []uint64
|
||||
userID uint64
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = decoded.Claims.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c, ok := decoded.Claims.(jwt.MapClaims); ok {
|
||||
userID, _ = strconv.ParseUint(c["userID"].(string), 10, 64)
|
||||
|
||||
if memberOf, ok := c["memberOf"].(string); ok {
|
||||
for _, str := range strings.Split(memberOf, " ") {
|
||||
if id, _ := strconv.ParseUint(str, 10, 64); id > 0 {
|
||||
rr = append(rr, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if userID > 0 {
|
||||
return NewIdentity(userID, rr...), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("invalid claims")
|
||||
|
||||
}
|
||||
|
||||
func (t *token) Encode(identity Identifiable) string {
|
||||
claims := jwt.MapClaims{
|
||||
"userID": strconv.FormatUint(identity.Identity(), 10),
|
||||
@@ -67,8 +102,8 @@ func (t *token) Encode(identity Identifiable) string {
|
||||
return jwt
|
||||
}
|
||||
|
||||
// Authenticator converts JWT claims into Identity and stores it into context
|
||||
func (t *token) Authenticator() func(http.Handler) http.Handler {
|
||||
// HttpAuthenticator converts JWT claims into Identity and stores it into context
|
||||
func (t *token) HttpAuthenticator() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
jwt, claims, err := jwtauth.FromContext(r.Context())
|
||||
@@ -94,7 +129,7 @@ func (t *token) Authenticator() func(http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
r = r.WithContext(SetIdentityToContext(r.Context(), identity))
|
||||
r = r.WithContext(SetJwtToContext(SetIdentityToContext(r.Context(), identity), jwt.Raw))
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
@@ -51,6 +51,8 @@ func Service(ctx context.Context, logger *zap.Logger, repository *repository) (s
|
||||
// use Check() to test against permission rules and
|
||||
// iterate over all fallback functions
|
||||
//
|
||||
// System user is always allowed to do everything
|
||||
//
|
||||
// When not explicitly allowed through rules or fallbacks, function will return FALSE.
|
||||
func (svc service) Can(ctx context.Context, res Resource, op Operation, ff ...CheckAccessFunc) bool {
|
||||
{
|
||||
@@ -62,7 +64,13 @@ func (svc service) Can(ctx context.Context, res Resource, op Operation, ff ...Ch
|
||||
}
|
||||
}
|
||||
|
||||
var roles = auth.GetIdentityFromContext(ctx).Roles()
|
||||
u := auth.GetIdentityFromContext(ctx)
|
||||
|
||||
if auth.IsSuperUser(u) {
|
||||
return true
|
||||
}
|
||||
|
||||
var roles = u.Roles()
|
||||
// Checking rules
|
||||
var v = svc.Check(res, op, roles...)
|
||||
if v != Inherit {
|
||||
|
||||
@@ -125,8 +125,8 @@ func (s Server) Serve(ctx context.Context) {
|
||||
|
||||
router.Group(func(r chi.Router) {
|
||||
r.Use(
|
||||
auth.DefaultJwtHandler.Verifier(),
|
||||
auth.DefaultJwtHandler.Authenticator(),
|
||||
auth.DefaultJwtHandler.HttpVerifier(),
|
||||
auth.DefaultJwtHandler.HttpAuthenticator(),
|
||||
)
|
||||
|
||||
for _, mountRoutes := range s.endpoints {
|
||||
|
||||
@@ -58,6 +58,12 @@ type (
|
||||
|
||||
// How are we merging?
|
||||
tms triggersMergeStrategy
|
||||
|
||||
// Script running credentials
|
||||
//
|
||||
// We'll store credentials for security-defined scripts
|
||||
// here when (runnable) scripts are loaded
|
||||
credentials string
|
||||
}
|
||||
|
||||
ScriptFilter struct {
|
||||
@@ -180,6 +186,10 @@ func (s Script) HasEvent(event string) bool {
|
||||
return s.triggers.HasMatch(Trigger{Event: event})
|
||||
}
|
||||
|
||||
func (s Script) Credentials() string {
|
||||
return s.credentials
|
||||
}
|
||||
|
||||
func MakeMatcherIDCondition(id uint64) TriggerConditionChecker {
|
||||
// We'll be comparing strings, not uint64!
|
||||
var s = strconv.FormatUint(id, 10)
|
||||
|
||||
@@ -26,6 +26,9 @@ type (
|
||||
// internal list of runnable scripts (and their accompanying triggers)
|
||||
runnables ScriptSet
|
||||
|
||||
// turns user-id (rel_runner / runAs) into valid credentials (JWT)
|
||||
makeToken TokenMaker
|
||||
|
||||
srepo *scriptRepository
|
||||
trepo *triggerRepository
|
||||
|
||||
@@ -36,6 +39,8 @@ type (
|
||||
FilterByTrigger(event, resource string, cc ...TriggerConditionChecker) ScriptSet
|
||||
}
|
||||
|
||||
TokenMaker func(context.Context, uint64) (string, error)
|
||||
|
||||
WatcherService interface {
|
||||
Watch(ctx context.Context)
|
||||
}
|
||||
@@ -43,6 +48,7 @@ type (
|
||||
AutomationServiceConfig struct {
|
||||
Logger *zap.Logger
|
||||
DB *factory.DB
|
||||
TokenMaker TokenMaker
|
||||
DbTablePrefix string
|
||||
}
|
||||
)
|
||||
@@ -62,6 +68,8 @@ func Service(c AutomationServiceConfig) (svc *service) {
|
||||
|
||||
c: c,
|
||||
|
||||
makeToken: c.TokenMaker,
|
||||
|
||||
srepo: ScriptRepository(c.DbTablePrefix),
|
||||
trepo: TriggerRepository(c.DbTablePrefix),
|
||||
|
||||
@@ -141,6 +149,24 @@ func (svc *service) reload(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
_ = svc.runnables.Walk(func(script *Script) (err error) {
|
||||
if script.RunAsDefined() {
|
||||
script.credentials, err = svc.makeToken(ctx, script.RunAs)
|
||||
|
||||
if err != nil {
|
||||
script.Enabled = false
|
||||
|
||||
svc.logger.Info(
|
||||
"could not make token, disabling script",
|
||||
zap.Uint64("runAs", script.RunAs),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return tt.Walk(func(t *Trigger) error {
|
||||
s := svc.runnables.FindByID(t.ScriptID)
|
||||
if s != nil && t.IsValid() && s.CheckCompatibility(t) == nil {
|
||||
|
||||
29
pkg/cli/options/grpc_server.go
Normal file
29
pkg/cli/options/grpc_server.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
GRPCServerOpt struct {
|
||||
Network string `env:"GRPC_SERVER_NETWORK"`
|
||||
Addr string `env:"GRPC_SERVER_ADDR"`
|
||||
|
||||
ClientMaxBackoffDelay time.Duration `env:"GRPC_CLIENT_BACKOFF_DELAY"`
|
||||
ClientLog bool `env:"GRPC_CLIENT_LOG"`
|
||||
}
|
||||
)
|
||||
|
||||
func GRPCServer(pfix string) (o *GRPCServerOpt) {
|
||||
o = &GRPCServerOpt{
|
||||
Network: "tcp",
|
||||
Addr: ":50051",
|
||||
|
||||
ClientMaxBackoffDelay: time.Minute,
|
||||
ClientLog: false,
|
||||
}
|
||||
|
||||
fill(o, pfix)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -52,6 +52,12 @@ type (
|
||||
StorageOpt *options.StorageOpt
|
||||
ScriptRunner *options.ScriptRunnerOpt
|
||||
|
||||
// Services will be calling each other so we need
|
||||
// to keep the config opts spearated
|
||||
GRPCServerSystem *options.GRPCServerOpt
|
||||
// GRPCServerMessaging *options.GRPCServerOpt
|
||||
// GRPCServerCompose *options.GRPCServerOpt
|
||||
|
||||
// DB Connection name, defaults to ServiceName
|
||||
DatabaseName string
|
||||
|
||||
@@ -190,6 +196,9 @@ func (c *Config) Init() {
|
||||
c.SentryOpt = options.Sentry(c.EnvPrefix)
|
||||
c.StorageOpt = options.Storage(c.EnvPrefix)
|
||||
c.ScriptRunner = options.ScriptRunner(c.EnvPrefix)
|
||||
c.GRPCServerSystem = options.GRPCServer("system")
|
||||
// c.GRPCServerCompose = options.GRPCServer("compose")
|
||||
// c.GRPCServerMessagign = options.GRPCServer("messaging")
|
||||
|
||||
if c.RootCommandDBSetup == nil {
|
||||
c.RootCommandDBSetup = Runners{func(ctx context.Context, cmd *cobra.Command, c *Config) (err error) {
|
||||
|
||||
53
system/grpc/server.go
Normal file
53
system/grpc/server.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/proto"
|
||||
)
|
||||
|
||||
// @todo when we extend gRPC-server capabilities to compose & messaging
|
||||
// this needs to be refactored and generalized
|
||||
func NewServer() *grpc.Server {
|
||||
s := grpc.NewServer(
|
||||
grpc.UnaryInterceptor(authCheck(auth.DefaultJwtHandler)),
|
||||
)
|
||||
|
||||
proto.RegisterUsersServer(s, NewUserService(
|
||||
service.DefaultUser,
|
||||
auth.DefaultJwtHandler,
|
||||
service.DefaultAccessControl,
|
||||
))
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Creates auth-checking interceptor function
|
||||
//
|
||||
// Interceptor expects a valid 'jwt' in meta-data
|
||||
func authCheck(h auth.TokenDecoder) grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
if meta, ok := metadata.FromIncomingContext(ctx); !ok {
|
||||
return nil, status.Error(codes.Unauthenticated, "could not read metadata")
|
||||
} else if len(meta["jwt"]) != 1 {
|
||||
return nil, status.Error(codes.Unauthenticated, "metadata without jwt")
|
||||
} else if identity, err := h.Decode(meta["jwt"][0]); err != nil {
|
||||
return nil, status.Error(codes.Unauthenticated, "invalid jwt")
|
||||
} else if identity == nil || !identity.Valid() {
|
||||
return nil, status.Error(codes.Unauthenticated, "invalid identity")
|
||||
} else {
|
||||
// Append identity to context and procede
|
||||
ctx = auth.SetIdentityToContext(ctx, identity)
|
||||
}
|
||||
|
||||
// Serve the request
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
75
system/grpc/users_service.go
Normal file
75
system/grpc/users_service.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/proto"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
userService struct {
|
||||
ac userServiceAccessControl
|
||||
svc service.UserService
|
||||
jwt auth.TokenEncoder
|
||||
}
|
||||
|
||||
userServiceAccessControl interface {
|
||||
CanGrant(ctx context.Context) bool
|
||||
}
|
||||
)
|
||||
|
||||
func NewUserService(svc service.UserService, jwt auth.TokenEncoder, ac userServiceAccessControl) *userService {
|
||||
return &userService{
|
||||
ac: ac,
|
||||
svc: svc,
|
||||
jwt: jwt,
|
||||
}
|
||||
}
|
||||
|
||||
func (gs userService) MakeJWT(ctx context.Context, req *proto.MakeJWTRequest) (rsp *proto.MakeJWTResponse, err error) {
|
||||
var (
|
||||
u *types.User
|
||||
)
|
||||
|
||||
if !gs.ac.CanGrant(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "no permissions to issue jwt for other users")
|
||||
}
|
||||
|
||||
if u, err = gs.svc.FindByID(req.UserID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rsp = &proto.MakeJWTResponse{
|
||||
JWT: gs.jwt.Encode(u),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (gs userService) FindByID(ctx context.Context, req *proto.FindByIDRequest) (rsp *proto.FindByIDResponse, err error) {
|
||||
var (
|
||||
u *types.User
|
||||
)
|
||||
|
||||
if u, err = gs.svc.FindByID(req.UserID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rsp = &proto.FindByIDResponse{
|
||||
User: &proto.User{
|
||||
ID: u.ID,
|
||||
Email: u.Email,
|
||||
Handle: u.Handle,
|
||||
Name: u.Name,
|
||||
Kind: string(u.Kind),
|
||||
},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
399
system/proto/user.pb.go
Normal file
399
system/proto/user.pb.go
Normal file
@@ -0,0 +1,399 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: user.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type MakeJWTRequest struct {
|
||||
UserID uint64 `protobuf:"varint,1,opt,name=userID,proto3" json:"userID,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MakeJWTRequest) Reset() { *m = MakeJWTRequest{} }
|
||||
func (m *MakeJWTRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*MakeJWTRequest) ProtoMessage() {}
|
||||
func (*MakeJWTRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_116e343673f7ffaf, []int{0}
|
||||
}
|
||||
|
||||
func (m *MakeJWTRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MakeJWTRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *MakeJWTRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_MakeJWTRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *MakeJWTRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MakeJWTRequest.Merge(m, src)
|
||||
}
|
||||
func (m *MakeJWTRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_MakeJWTRequest.Size(m)
|
||||
}
|
||||
func (m *MakeJWTRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MakeJWTRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MakeJWTRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *MakeJWTRequest) GetUserID() uint64 {
|
||||
if m != nil {
|
||||
return m.UserID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type MakeJWTResponse struct {
|
||||
JWT string `protobuf:"bytes,1,opt,name=JWT,proto3" json:"JWT,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MakeJWTResponse) Reset() { *m = MakeJWTResponse{} }
|
||||
func (m *MakeJWTResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*MakeJWTResponse) ProtoMessage() {}
|
||||
func (*MakeJWTResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_116e343673f7ffaf, []int{1}
|
||||
}
|
||||
|
||||
func (m *MakeJWTResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MakeJWTResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *MakeJWTResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_MakeJWTResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *MakeJWTResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MakeJWTResponse.Merge(m, src)
|
||||
}
|
||||
func (m *MakeJWTResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_MakeJWTResponse.Size(m)
|
||||
}
|
||||
func (m *MakeJWTResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MakeJWTResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MakeJWTResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *MakeJWTResponse) GetJWT() string {
|
||||
if m != nil {
|
||||
return m.JWT
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type FindByIDRequest struct {
|
||||
UserID uint64 `protobuf:"varint,1,opt,name=userID,proto3" json:"userID,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FindByIDRequest) Reset() { *m = FindByIDRequest{} }
|
||||
func (m *FindByIDRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindByIDRequest) ProtoMessage() {}
|
||||
func (*FindByIDRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_116e343673f7ffaf, []int{2}
|
||||
}
|
||||
|
||||
func (m *FindByIDRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FindByIDRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FindByIDRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FindByIDRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FindByIDRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FindByIDRequest.Merge(m, src)
|
||||
}
|
||||
func (m *FindByIDRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_FindByIDRequest.Size(m)
|
||||
}
|
||||
func (m *FindByIDRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FindByIDRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FindByIDRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *FindByIDRequest) GetUserID() uint64 {
|
||||
if m != nil {
|
||||
return m.UserID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type FindByIDResponse struct {
|
||||
User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FindByIDResponse) Reset() { *m = FindByIDResponse{} }
|
||||
func (m *FindByIDResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindByIDResponse) ProtoMessage() {}
|
||||
func (*FindByIDResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_116e343673f7ffaf, []int{3}
|
||||
}
|
||||
|
||||
func (m *FindByIDResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FindByIDResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FindByIDResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FindByIDResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FindByIDResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FindByIDResponse.Merge(m, src)
|
||||
}
|
||||
func (m *FindByIDResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_FindByIDResponse.Size(m)
|
||||
}
|
||||
func (m *FindByIDResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FindByIDResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FindByIDResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *FindByIDResponse) GetUser() *User {
|
||||
if m != nil {
|
||||
return m.User
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
|
||||
Handle string `protobuf:"bytes,3,opt,name=handle,proto3" json:"handle,omitempty"`
|
||||
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Kind string `protobuf:"bytes,5,opt,name=kind,proto3" json:"kind,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *User) Reset() { *m = User{} }
|
||||
func (m *User) String() string { return proto.CompactTextString(m) }
|
||||
func (*User) ProtoMessage() {}
|
||||
func (*User) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_116e343673f7ffaf, []int{4}
|
||||
}
|
||||
|
||||
func (m *User) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_User.Unmarshal(m, b)
|
||||
}
|
||||
func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_User.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *User) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_User.Merge(m, src)
|
||||
}
|
||||
func (m *User) XXX_Size() int {
|
||||
return xxx_messageInfo_User.Size(m)
|
||||
}
|
||||
func (m *User) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_User.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_User proto.InternalMessageInfo
|
||||
|
||||
func (m *User) GetID() uint64 {
|
||||
if m != nil {
|
||||
return m.ID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *User) GetEmail() string {
|
||||
if m != nil {
|
||||
return m.Email
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *User) GetHandle() string {
|
||||
if m != nil {
|
||||
return m.Handle
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *User) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *User) GetKind() string {
|
||||
if m != nil {
|
||||
return m.Kind
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*MakeJWTRequest)(nil), "system.MakeJWTRequest")
|
||||
proto.RegisterType((*MakeJWTResponse)(nil), "system.MakeJWTResponse")
|
||||
proto.RegisterType((*FindByIDRequest)(nil), "system.FindByIDRequest")
|
||||
proto.RegisterType((*FindByIDResponse)(nil), "system.FindByIDResponse")
|
||||
proto.RegisterType((*User)(nil), "system.User")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("user.proto", fileDescriptor_116e343673f7ffaf) }
|
||||
|
||||
var fileDescriptor_116e343673f7ffaf = []byte{
|
||||
// 269 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xbf, 0x4b, 0xc3, 0x40,
|
||||
0x14, 0xc7, 0x49, 0x7a, 0x49, 0xf5, 0x29, 0x6d, 0x79, 0x48, 0x3d, 0x3a, 0x95, 0xb8, 0xd4, 0x25,
|
||||
0x43, 0x75, 0x12, 0x5c, 0x4a, 0x10, 0x52, 0x70, 0x09, 0x95, 0x82, 0x5b, 0x24, 0x0f, 0x0c, 0x4d,
|
||||
0x2e, 0x35, 0x97, 0x0e, 0x5d, 0xfd, 0xcb, 0xe5, 0x5e, 0xae, 0x11, 0xcd, 0xd0, 0x29, 0xef, 0xfb,
|
||||
0x7d, 0x9f, 0xbc, 0x5f, 0x07, 0x70, 0xd0, 0x54, 0x87, 0xfb, 0xba, 0x6a, 0x2a, 0xf4, 0xf5, 0x51,
|
||||
0x37, 0x54, 0x06, 0x0b, 0x18, 0xbd, 0xa6, 0x3b, 0x5a, 0x6f, 0x37, 0x09, 0x7d, 0x1d, 0x48, 0x37,
|
||||
0x38, 0x05, 0xdf, 0x70, 0x71, 0x24, 0x9d, 0xb9, 0xb3, 0x10, 0x89, 0x55, 0xc1, 0x1d, 0x8c, 0x3b,
|
||||
0x52, 0xef, 0x2b, 0xa5, 0x09, 0x27, 0x30, 0x58, 0x6f, 0x37, 0xcc, 0x5d, 0x26, 0x26, 0x0c, 0xee,
|
||||
0x61, 0xfc, 0x92, 0xab, 0x6c, 0x75, 0x8c, 0xa3, 0x73, 0xf5, 0x1e, 0x61, 0xf2, 0x8b, 0xda, 0x82,
|
||||
0x73, 0x10, 0x26, 0xcb, 0xe4, 0xd5, 0xf2, 0x3a, 0x6c, 0x87, 0x0c, 0xdf, 0x34, 0xd5, 0x09, 0x67,
|
||||
0x82, 0x02, 0x84, 0x51, 0x38, 0x02, 0xb7, 0xab, 0xe8, 0xc6, 0x11, 0xde, 0x80, 0x47, 0x65, 0x9a,
|
||||
0x17, 0xd2, 0xe5, 0x61, 0x5a, 0x61, 0x7a, 0x7f, 0xa6, 0x2a, 0x2b, 0x48, 0x0e, 0xd8, 0xb6, 0x0a,
|
||||
0x11, 0x84, 0x4a, 0x4b, 0x92, 0x82, 0x5d, 0x8e, 0x8d, 0xb7, 0xcb, 0x55, 0x26, 0xbd, 0xd6, 0x33,
|
||||
0xf1, 0xf2, 0xdb, 0x01, 0xcf, 0xb4, 0xd3, 0xf8, 0x04, 0x43, 0xbb, 0x3d, 0x4e, 0x4f, 0x63, 0xfd,
|
||||
0x3d, 0xdc, 0xec, 0xb6, 0xe7, 0xdb, 0xad, 0x9e, 0xe1, 0xe2, 0xb4, 0x29, 0x76, 0xd0, 0xbf, 0x33,
|
||||
0xcd, 0x64, 0x3f, 0xd1, 0xfe, 0xbe, 0x1a, 0xbe, 0x7b, 0xfc, 0x66, 0x1f, 0x3e, 0x7f, 0x1e, 0x7e,
|
||||
0x02, 0x00, 0x00, 0xff, 0xff, 0x04, 0x91, 0x4b, 0x16, 0xc8, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// UsersClient is the client API for Users service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type UsersClient interface {
|
||||
MakeJWT(ctx context.Context, in *MakeJWTRequest, opts ...grpc.CallOption) (*MakeJWTResponse, error)
|
||||
FindByID(ctx context.Context, in *FindByIDRequest, opts ...grpc.CallOption) (*FindByIDResponse, error)
|
||||
}
|
||||
|
||||
type usersClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewUsersClient(cc *grpc.ClientConn) UsersClient {
|
||||
return &usersClient{cc}
|
||||
}
|
||||
|
||||
func (c *usersClient) MakeJWT(ctx context.Context, in *MakeJWTRequest, opts ...grpc.CallOption) (*MakeJWTResponse, error) {
|
||||
out := new(MakeJWTResponse)
|
||||
err := c.cc.Invoke(ctx, "/system.Users/MakeJWT", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *usersClient) FindByID(ctx context.Context, in *FindByIDRequest, opts ...grpc.CallOption) (*FindByIDResponse, error) {
|
||||
out := new(FindByIDResponse)
|
||||
err := c.cc.Invoke(ctx, "/system.Users/FindByID", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UsersServer is the server API for Users service.
|
||||
type UsersServer interface {
|
||||
MakeJWT(context.Context, *MakeJWTRequest) (*MakeJWTResponse, error)
|
||||
FindByID(context.Context, *FindByIDRequest) (*FindByIDResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedUsersServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedUsersServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedUsersServer) MakeJWT(ctx context.Context, req *MakeJWTRequest) (*MakeJWTResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method MakeJWT not implemented")
|
||||
}
|
||||
func (*UnimplementedUsersServer) FindByID(ctx context.Context, req *FindByIDRequest) (*FindByIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FindByID not implemented")
|
||||
}
|
||||
|
||||
func RegisterUsersServer(s *grpc.Server, srv UsersServer) {
|
||||
s.RegisterService(&_Users_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Users_MakeJWT_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(MakeJWTRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UsersServer).MakeJWT(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/system.Users/MakeJWT",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UsersServer).MakeJWT(ctx, req.(*MakeJWTRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Users_FindByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(FindByIDRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UsersServer).FindByID(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/system.Users/FindByID",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UsersServer).FindByID(ctx, req.(*FindByIDRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Users_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "system.Users",
|
||||
HandlerType: (*UsersServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "MakeJWT",
|
||||
Handler: _Users_MakeJWT_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "FindByID",
|
||||
Handler: _Users_FindByID_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "user.proto",
|
||||
}
|
||||
@@ -2,14 +2,17 @@ package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/system/commands"
|
||||
migrate "github.com/cortezaproject/corteza-server/system/db"
|
||||
"github.com/cortezaproject/corteza-server/system/grpc"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/auth/external"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest"
|
||||
@@ -69,6 +72,36 @@ func Configure() *cli.Config {
|
||||
service.DefaultAuthSettings, _ = service.DefaultSettings.LoadAuthSettings()
|
||||
}
|
||||
|
||||
{
|
||||
var (
|
||||
grpcLog = c.Log.Named("grpc-server")
|
||||
grpcLogConn = grpcLog.With(zap.String("addr", c.GRPCServerSystem.Addr))
|
||||
)
|
||||
|
||||
// Temporary gRPC server initialization location
|
||||
grpcServer := grpc.NewServer()
|
||||
|
||||
ln, err := net.Listen(c.GRPCServerSystem.Network, c.GRPCServerSystem.Addr)
|
||||
if err != nil {
|
||||
grpcLogConn.Error("could not start gRPC server", zap.Error(err))
|
||||
}
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
grpcLogConn.Debug("shutting down")
|
||||
grpcServer.GracefulStop()
|
||||
_ = ln.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
grpcLogConn.Info("Starting gRPC server")
|
||||
err := grpcServer.Serve(ln)
|
||||
grpcLogConn.Info("stopped", zap.Error(err))
|
||||
}()
|
||||
}
|
||||
|
||||
// Initialize external authentication (from default settings)
|
||||
external.Init()
|
||||
go service.Watchers(ctx)
|
||||
|
||||
Reference in New Issue
Block a user