From 45768b0bdccf9621a0570a2aa70e21e8f1283775 Mon Sep 17 00:00:00 2001 From: Mirko Teodorovic Date: Tue, 15 Dec 2020 11:35:53 +0100 Subject: [PATCH 01/20] remove owner id Signed-off-by: Mirko Teodorovic --- users/postgres/init.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/users/postgres/init.go b/users/postgres/init.go index 821c802ac7..34a15aabdf 100644 --- a/users/postgres/init.go +++ b/users/postgres/init.go @@ -78,6 +78,13 @@ func migrateDB(db *sqlx.DB) error { `ALTER TABLE IF EXISTS users ADD PRIMARY KEY (id)`, }, }, + { + Id: "users_5", + Up: []string{ + `ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS users_owner_id_fkey`, + `ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS owner_id`, + }, + }, }, } From 228ab1d712830407657192ac6e566030d0d755ad Mon Sep 17 00:00:00 2001 From: mteodor Date: Thu, 24 Jun 2021 15:48:53 +0200 Subject: [PATCH 02/20] remove auth service, use OIDC access token forwarded from proxy in Authorization header Signed-off-by: mteodor --- cmd/things/main.go | 14 ++++----- docker/.env | 2 +- things/service.go | 74 ++++++++++++++++++++++++++++------------------ 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/cmd/things/main.go b/cmd/things/main.go index a5cddccd1c..872da20a13 100644 --- a/cmd/things/main.go +++ b/cmd/things/main.go @@ -142,13 +142,13 @@ func main() { db := connectToDB(cfg.dbConfig, logger) defer db.Close() - authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) - defer authCloser.Close() + // authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) + // defer authCloser.Close() - auth, close := createAuthClient(cfg, authTracer, logger) - if close != nil { - defer close() - } + // auth, close := createAuthClient(cfg, authTracer, logger) + // if close != nil { + // defer close() + // } dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) defer dbCloser.Close() @@ -156,7 +156,7 @@ func main() { cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) defer cacheCloser.Close() - svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, logger) + svc := newService(nil, dbTracer, cacheTracer, db, cacheClient, esClient, logger) errs := make(chan error, 2) go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc), cfg.httpPort, cfg, logger, errs) diff --git a/docker/.env b/docker/.env index 3d681d44a9..e091d15100 100644 --- a/docker/.env +++ b/docker/.env @@ -236,7 +236,7 @@ MF_MONGO_WRITER_PORT=8901 MF_MONGO_WRITER_DB=mainflux MF_MONGO_WRITER_DB_PORT=27017 MF_MONGO_WRITER_CONTENT_TYPE=application/senml+json -MF_MONGO_WRITER_TRANSFORMER=senml +MF_MONGO_WRITER_TRANSFORMER=json ### MongoDB Reader MF_MONGO_READER_LOG_LEVEL=debug diff --git a/things/service.go b/things/service.go index ab1a6b00f9..e01e352532 100644 --- a/things/service.go +++ b/things/service.go @@ -5,6 +5,8 @@ package things import ( "context" + "encoding/json" + "fmt" "github.com/mainflux/mainflux/pkg/errors" @@ -160,8 +162,22 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } } +func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + fmt.Printf("Token: %v\n", token) + defer fmt.Printf("Response %v, err: %v\n", u, err) + var jwt map[string]interface{} + if err = json.Unmarshal([]byte(token), &jwt); err != nil { + return nil, err + } + + return &mainflux.UserIdentity{ + Id: jwt["sub"].(string), + Email: jwt["email"].(string), + }, nil +} + func (ts *thingsService) CreateThings(ctx context.Context, token string, things ...Thing) ([]Thing, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return []Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -172,7 +188,7 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things return []Thing{}, errors.Wrap(ErrCreateUUID, err) } - things[i].Owner = res.GetEmail() + things[i].Owner = res.GetId() if things[i].Key == "" { things[i].Key, err = ts.idProvider.ID() @@ -186,56 +202,56 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things } func (ts *thingsService) UpdateThing(ctx context.Context, token string, thing Thing) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - thing.Owner = res.GetEmail() + thing.Owner = res.GetId() return ts.things.Update(ctx, thing) } func (ts *thingsService) UpdateKey(ctx context.Context, token, id, key string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - owner := res.GetEmail() + owner := res.GetId() return ts.things.UpdateKey(ctx, owner, id, key) } func (ts *thingsService) ViewThing(ctx context.Context, token, id string) (Thing, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveByID(ctx, res.GetEmail(), id) + return ts.things.RetrieveByID(ctx, res.GetId(), id) } func (ts *thingsService) ListThings(ctx context.Context, token string, pm PageMetadata) (Page, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveAll(ctx, res.GetEmail(), pm) + return ts.things.RetrieveAll(ctx, res.GetId(), pm) } func (ts *thingsService) ListThingsByChannel(ctx context.Context, token, chID string, pm PageMetadata) (Page, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveByChannel(ctx, res.GetEmail(), chID, pm) + return ts.things.RetrieveByChannel(ctx, res.GetId(), chID, pm) } func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -243,11 +259,11 @@ func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) erro if err := ts.thingCache.Remove(ctx, id); err != nil { return err } - return ts.things.Remove(ctx, res.GetEmail(), id) + return ts.things.Remove(ctx, res.GetId(), id) } func (ts *thingsService) CreateChannels(ctx context.Context, token string, channels ...Channel) ([]Channel, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return []Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -258,51 +274,51 @@ func (ts *thingsService) CreateChannels(ctx context.Context, token string, chann return []Channel{}, errors.Wrap(ErrCreateUUID, err) } - channels[i].Owner = res.GetEmail() + channels[i].Owner = res.GetId() } return ts.channels.Save(ctx, channels...) } func (ts *thingsService) UpdateChannel(ctx context.Context, token string, channel Channel) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - channel.Owner = res.GetEmail() + channel.Owner = res.GetId() return ts.channels.Update(ctx, channel) } func (ts *thingsService) ViewChannel(ctx context.Context, token, id string) (Channel, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveByID(ctx, res.GetEmail(), id) + return ts.channels.RetrieveByID(ctx, res.GetId(), id) } func (ts *thingsService) ListChannels(ctx context.Context, token string, pm PageMetadata) (ChannelsPage, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveAll(ctx, res.GetEmail(), pm) + return ts.channels.RetrieveAll(ctx, res.GetId(), pm) } func (ts *thingsService) ListChannelsByThing(ctx context.Context, token, thID string, pm PageMetadata) (ChannelsPage, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveByThing(ctx, res.GetEmail(), thID, pm) + return ts.channels.RetrieveByThing(ctx, res.GetId(), thID, pm) } func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -311,20 +327,20 @@ func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) er return err } - return ts.channels.Remove(ctx, res.GetEmail(), id) + return ts.channels.Remove(ctx, res.GetId(), id) } func (ts *thingsService) Connect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.Connect(ctx, res.GetEmail(), chIDs, thIDs) + return ts.channels.Connect(ctx, res.GetId(), chIDs, thIDs) } func (ts *thingsService) Disconnect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } From 8f21d734d03ad7b5d409e51380025f4972aef585 Mon Sep 17 00:00:00 2001 From: mteodor Date: Sat, 3 Jul 2021 00:41:05 +0200 Subject: [PATCH 03/20] remove printf Signed-off-by: mteodor --- things/service.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/things/service.go b/things/service.go index e01e352532..5f9af73e0b 100644 --- a/things/service.go +++ b/things/service.go @@ -6,7 +6,6 @@ package things import ( "context" "encoding/json" - "fmt" "github.com/mainflux/mainflux/pkg/errors" @@ -163,8 +162,6 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { - fmt.Printf("Token: %v\n", token) - defer fmt.Printf("Response %v, err: %v\n", u, err) var jwt map[string]interface{} if err = json.Unmarshal([]byte(token), &jwt); err != nil { return nil, err From dd4684a45102c3c7dc7c5120ad97a82a1c02c45b Mon Sep 17 00:00:00 2001 From: mteodor Date: Tue, 24 Aug 2021 12:21:22 +0200 Subject: [PATCH 04/20] fix parsing token Signed-off-by: mteodor --- things/service.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/things/service.go b/things/service.go index 5f9af73e0b..ccb80c4757 100644 --- a/things/service.go +++ b/things/service.go @@ -5,8 +5,9 @@ package things import ( "context" - "encoding/json" + "strings" + "github.com/dgrijalva/jwt-go" "github.com/mainflux/mainflux/pkg/errors" "github.com/mainflux/mainflux" @@ -162,14 +163,27 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { - var jwt map[string]interface{} - if err = json.Unmarshal([]byte(token), &jwt); err != nil { - return nil, err + if len(token) == 0 { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + // if parsed == nil || !parsed.Valid { + // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + // } + // TODO - Token should be properly validated + // to validate we need a public key + // it should be possible to get a public key from the token itself + if parsed == nil { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) return &mainflux.UserIdentity{ - Id: jwt["sub"].(string), - Email: jwt["email"].(string), + Id: claims["sub"].(string), + Email: claims["email"].(string), }, nil } From c5e296d7a50075fde33095b06d87a3585bf954c9 Mon Sep 17 00:00:00 2001 From: mteodor Date: Tue, 24 Aug 2021 14:31:17 +0200 Subject: [PATCH 05/20] replace jwt lib Signed-off-by: mteodor --- things/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/things/service.go b/things/service.go index ccb80c4757..56fab46d0b 100644 --- a/things/service.go +++ b/things/service.go @@ -7,7 +7,7 @@ import ( "context" "strings" - "github.com/dgrijalva/jwt-go" + "github.com/golang-jwt/jwt/v4" "github.com/mainflux/mainflux/pkg/errors" "github.com/mainflux/mainflux" From 052dd1f49b82cbe7c9484692c967e70fb7dcf068 Mon Sep 17 00:00:00 2001 From: Mirko Teodorovic Date: Tue, 15 Dec 2020 11:35:53 +0100 Subject: [PATCH 06/20] remove owner id Signed-off-by: Mirko Teodorovic --- users/postgres/init.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/users/postgres/init.go b/users/postgres/init.go index 821c802ac7..34a15aabdf 100644 --- a/users/postgres/init.go +++ b/users/postgres/init.go @@ -78,6 +78,13 @@ func migrateDB(db *sqlx.DB) error { `ALTER TABLE IF EXISTS users ADD PRIMARY KEY (id)`, }, }, + { + Id: "users_5", + Up: []string{ + `ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS users_owner_id_fkey`, + `ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS owner_id`, + }, + }, }, } From b9cae138ffdaaa3795858c434a3a046e012d8f78 Mon Sep 17 00:00:00 2001 From: mteodor Date: Thu, 24 Jun 2021 15:48:53 +0200 Subject: [PATCH 07/20] remove auth service, use OIDC access token forwarded from proxy in Authorization header Signed-off-by: mteodor --- cmd/things/main.go | 14 ++++----- docker/.env | 2 +- things/service.go | 71 +++++++++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/cmd/things/main.go b/cmd/things/main.go index a5cddccd1c..872da20a13 100644 --- a/cmd/things/main.go +++ b/cmd/things/main.go @@ -142,13 +142,13 @@ func main() { db := connectToDB(cfg.dbConfig, logger) defer db.Close() - authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) - defer authCloser.Close() + // authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) + // defer authCloser.Close() - auth, close := createAuthClient(cfg, authTracer, logger) - if close != nil { - defer close() - } + // auth, close := createAuthClient(cfg, authTracer, logger) + // if close != nil { + // defer close() + // } dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) defer dbCloser.Close() @@ -156,7 +156,7 @@ func main() { cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) defer cacheCloser.Close() - svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, logger) + svc := newService(nil, dbTracer, cacheTracer, db, cacheClient, esClient, logger) errs := make(chan error, 2) go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc), cfg.httpPort, cfg, logger, errs) diff --git a/docker/.env b/docker/.env index 3d681d44a9..e091d15100 100644 --- a/docker/.env +++ b/docker/.env @@ -236,7 +236,7 @@ MF_MONGO_WRITER_PORT=8901 MF_MONGO_WRITER_DB=mainflux MF_MONGO_WRITER_DB_PORT=27017 MF_MONGO_WRITER_CONTENT_TYPE=application/senml+json -MF_MONGO_WRITER_TRANSFORMER=senml +MF_MONGO_WRITER_TRANSFORMER=json ### MongoDB Reader MF_MONGO_READER_LOG_LEVEL=debug diff --git a/things/service.go b/things/service.go index ab1a6b00f9..5f9af73e0b 100644 --- a/things/service.go +++ b/things/service.go @@ -5,6 +5,7 @@ package things import ( "context" + "encoding/json" "github.com/mainflux/mainflux/pkg/errors" @@ -160,8 +161,20 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } } +func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + var jwt map[string]interface{} + if err = json.Unmarshal([]byte(token), &jwt); err != nil { + return nil, err + } + + return &mainflux.UserIdentity{ + Id: jwt["sub"].(string), + Email: jwt["email"].(string), + }, nil +} + func (ts *thingsService) CreateThings(ctx context.Context, token string, things ...Thing) ([]Thing, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return []Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -172,7 +185,7 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things return []Thing{}, errors.Wrap(ErrCreateUUID, err) } - things[i].Owner = res.GetEmail() + things[i].Owner = res.GetId() if things[i].Key == "" { things[i].Key, err = ts.idProvider.ID() @@ -186,56 +199,56 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things } func (ts *thingsService) UpdateThing(ctx context.Context, token string, thing Thing) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - thing.Owner = res.GetEmail() + thing.Owner = res.GetId() return ts.things.Update(ctx, thing) } func (ts *thingsService) UpdateKey(ctx context.Context, token, id, key string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - owner := res.GetEmail() + owner := res.GetId() return ts.things.UpdateKey(ctx, owner, id, key) } func (ts *thingsService) ViewThing(ctx context.Context, token, id string) (Thing, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveByID(ctx, res.GetEmail(), id) + return ts.things.RetrieveByID(ctx, res.GetId(), id) } func (ts *thingsService) ListThings(ctx context.Context, token string, pm PageMetadata) (Page, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveAll(ctx, res.GetEmail(), pm) + return ts.things.RetrieveAll(ctx, res.GetId(), pm) } func (ts *thingsService) ListThingsByChannel(ctx context.Context, token, chID string, pm PageMetadata) (Page, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.things.RetrieveByChannel(ctx, res.GetEmail(), chID, pm) + return ts.things.RetrieveByChannel(ctx, res.GetId(), chID, pm) } func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -243,11 +256,11 @@ func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) erro if err := ts.thingCache.Remove(ctx, id); err != nil { return err } - return ts.things.Remove(ctx, res.GetEmail(), id) + return ts.things.Remove(ctx, res.GetId(), id) } func (ts *thingsService) CreateChannels(ctx context.Context, token string, channels ...Channel) ([]Channel, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return []Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -258,51 +271,51 @@ func (ts *thingsService) CreateChannels(ctx context.Context, token string, chann return []Channel{}, errors.Wrap(ErrCreateUUID, err) } - channels[i].Owner = res.GetEmail() + channels[i].Owner = res.GetId() } return ts.channels.Save(ctx, channels...) } func (ts *thingsService) UpdateChannel(ctx context.Context, token string, channel Channel) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - channel.Owner = res.GetEmail() + channel.Owner = res.GetId() return ts.channels.Update(ctx, channel) } func (ts *thingsService) ViewChannel(ctx context.Context, token, id string) (Channel, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveByID(ctx, res.GetEmail(), id) + return ts.channels.RetrieveByID(ctx, res.GetId(), id) } func (ts *thingsService) ListChannels(ctx context.Context, token string, pm PageMetadata) (ChannelsPage, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveAll(ctx, res.GetEmail(), pm) + return ts.channels.RetrieveAll(ctx, res.GetId(), pm) } func (ts *thingsService) ListChannelsByThing(ctx context.Context, token, thID string, pm PageMetadata) (ChannelsPage, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.RetrieveByThing(ctx, res.GetEmail(), thID, pm) + return ts.channels.RetrieveByThing(ctx, res.GetId(), thID, pm) } func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -311,20 +324,20 @@ func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) er return err } - return ts.channels.Remove(ctx, res.GetEmail(), id) + return ts.channels.Remove(ctx, res.GetId(), id) } func (ts *thingsService) Connect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - return ts.channels.Connect(ctx, res.GetEmail(), chIDs, thIDs) + return ts.channels.Connect(ctx, res.GetId(), chIDs, thIDs) } func (ts *thingsService) Disconnect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } From 465aa337308e0f847051860048ce260887ad2357 Mon Sep 17 00:00:00 2001 From: mteodor Date: Sat, 3 Jul 2021 13:10:45 +0200 Subject: [PATCH 08/20] default json writer to senml Signed-off-by: mteodor --- docker/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/.env b/docker/.env index e091d15100..3d681d44a9 100644 --- a/docker/.env +++ b/docker/.env @@ -236,7 +236,7 @@ MF_MONGO_WRITER_PORT=8901 MF_MONGO_WRITER_DB=mainflux MF_MONGO_WRITER_DB_PORT=27017 MF_MONGO_WRITER_CONTENT_TYPE=application/senml+json -MF_MONGO_WRITER_TRANSFORMER=json +MF_MONGO_WRITER_TRANSFORMER=senml ### MongoDB Reader MF_MONGO_READER_LOG_LEVEL=debug From 63a4de1b0ce41ec61f13c7295f82f3917db9d753 Mon Sep 17 00:00:00 2001 From: mteodor Date: Wed, 1 Sep 2021 17:29:24 +0200 Subject: [PATCH 09/20] add support for authorization token in readers Signed-off-by: mteodor --- readers/api/transport.go | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/readers/api/transport.go b/readers/api/transport.go index 0f85330ab7..98705bda88 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -8,10 +8,13 @@ import ( "encoding/json" "net/http" "strconv" + "strings" "time" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-zoo/bone" + "github.com/gofrs/uuid" + "github.com/golang-jwt/jwt/v4" "github.com/mainflux/mainflux" "github.com/mainflux/mainflux/internal/httputil" "github.com/mainflux/mainflux/pkg/errors" @@ -219,16 +222,31 @@ func authorize(r *http.Request, chanID string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - _, err := auth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: chanID}) - if err != nil { - e, ok := status.FromError(err) - if ok && e.Code() == codes.PermissionDenied { - return errUnauthorizedAccess + if _, err := uuid.FromString(token); err != nil { + _, err := auth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: chanID}) + if err != nil { + e, ok := status.FromError(err) + if ok && e.Code() == codes.PermissionDenied { + return errUnauthorizedAccess + } + return err } - return err + return nil } - return nil + if u, err := identify(ctx, token); err != nil { + _, err := auth.IsChannelOwner(ctx, &mainflux.ChannelOwnerReq{Owner: u.Id, ChanID: chanID}) + if err != nil { + e, ok := status.FromError(err) + if ok && e.Code() == codes.PermissionDenied { + return errUnauthorizedAccess + } + return err + } + return nil + } + + return errUnauthorizedAccess } func readBoolValueQuery(r *http.Request, key string) (bool, error) { @@ -248,3 +266,28 @@ func readBoolValueQuery(r *http.Request, key string) (bool, error) { return b, nil } + +func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + if len(token) == 0 { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Empty authorization token")) + } + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + // if parsed == nil || !parsed.Valid { + // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + // } + // TODO - Token should be properly validated + // to validate we need a public key + // it should be possible to get a public key from the token itself + if parsed == nil { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) + + return &mainflux.UserIdentity{ + Id: claims["sub"].(string), + Email: claims["email"].(string), + }, nil +} From 5aca8e72f9498d8e2f80309e035bb014839629c7 Mon Sep 17 00:00:00 2001 From: mteodor Date: Wed, 1 Sep 2021 17:57:34 +0200 Subject: [PATCH 10/20] fix token handling Signed-off-by: mteodor --- things/service.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/things/service.go b/things/service.go index 5f9af73e0b..56fab46d0b 100644 --- a/things/service.go +++ b/things/service.go @@ -5,8 +5,9 @@ package things import ( "context" - "encoding/json" + "strings" + "github.com/golang-jwt/jwt/v4" "github.com/mainflux/mainflux/pkg/errors" "github.com/mainflux/mainflux" @@ -162,14 +163,27 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { - var jwt map[string]interface{} - if err = json.Unmarshal([]byte(token), &jwt); err != nil { - return nil, err + if len(token) == 0 { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + // if parsed == nil || !parsed.Valid { + // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + // } + // TODO - Token should be properly validated + // to validate we need a public key + // it should be possible to get a public key from the token itself + if parsed == nil { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) return &mainflux.UserIdentity{ - Id: jwt["sub"].(string), - Email: jwt["email"].(string), + Id: claims["sub"].(string), + Email: claims["email"].(string), }, nil } From 6f9664969b24f580471327fdee74b0576a690539 Mon Sep 17 00:00:00 2001 From: mteodor Date: Mon, 6 Sep 2021 11:46:06 +0200 Subject: [PATCH 11/20] add errors Signed-off-by: mteodor --- readers/api/transport.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/readers/api/transport.go b/readers/api/transport.go index 98705bda88..4654e27819 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -45,8 +45,11 @@ const ( ) var ( - errUnauthorizedAccess = errors.New("missing or invalid credentials provided") - auth mainflux.ThingsServiceClient + errUnauthorizedAccess = errors.New("missing or invalid credentials provided") + errMissingAuthorizationHeader = errors.New("missing authorization header") + errChannelThingConnectionMissing = errors.New("channel is not connected to a thing") + errNotChannelOwner = errors.New("user is not the owner of channel") + auth mainflux.ThingsServiceClient ) // MakeHandler returns a HTTP handler for API endpoints. @@ -222,24 +225,24 @@ func authorize(r *http.Request, chanID string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - if _, err := uuid.FromString(token); err != nil { + if _, err := uuid.FromString(token); err == nil { _, err := auth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: chanID}) if err != nil { e, ok := status.FromError(err) if ok && e.Code() == codes.PermissionDenied { - return errUnauthorizedAccess + return errors.Wrap(errUnauthorizedAccess, errChannelThingConnectionMissing) } return err } return nil } - if u, err := identify(ctx, token); err != nil { + if u, err := identify(ctx, token); err == nil { _, err := auth.IsChannelOwner(ctx, &mainflux.ChannelOwnerReq{Owner: u.Id, ChanID: chanID}) if err != nil { e, ok := status.FromError(err) if ok && e.Code() == codes.PermissionDenied { - return errUnauthorizedAccess + return errors.Wrap(errUnauthorizedAccess, errNotChannelOwner) } return err } From 947750407fdcacb125cf60cd289250ec59d2eb24 Mon Sep 17 00:00:00 2001 From: mteodor Date: Tue, 7 Sep 2021 13:17:02 +0200 Subject: [PATCH 12/20] add release tag to Makefile Signed-off-by: mteodor --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 990d5a2dea..0d2ce0628d 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 MF_DOCKER_IMAGE_NAME_PREFIX ?= mainflux +MF_RELEASE ?= latest BUILD_DIR = build SERVICES = users things http coap lora influxdb-writer influxdb-reader mongodb-writer \ mongodb-reader cassandra-writer cassandra-reader postgres-writer postgres-reader cli \ @@ -23,7 +24,7 @@ define make_docker --build-arg SVC=$(svc) \ --build-arg GOARCH=$(GOARCH) \ --build-arg GOARM=$(GOARM) \ - --tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \ + --tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc):$(MF_RELEASE) \ -f docker/Dockerfile . endef @@ -33,7 +34,7 @@ define make_docker_dev docker build \ --no-cache \ --build-arg SVC=$(svc) \ - --tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \ + --tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc):$(MF_RELEASE) \ -f docker/Dockerfile.dev ./build endef From b0cb1218e09950433ee40531ccb06d37406248f0 Mon Sep 17 00:00:00 2001 From: mteodor Date: Sun, 17 Oct 2021 09:18:03 +0200 Subject: [PATCH 13/20] add oidc support for additional services Signed-off-by: mteodor --- cmd/twins/main.go | 13 ++++++- cmd/users/main.go | 16 ++++++++- pkg/sdk/go/users_test.go | 2 +- readers/api/transport.go | 53 ++++++++++++++------------- things/service.go | 39 +++++++++++--------- twins/service.go | 46 ++++++++++++++++++++---- users/api/endpoint_test.go | 2 +- users/postgres/init.go | 7 ---- users/service.go | 74 +++++++++++++++++++++++++++++--------- users/service_test.go | 2 +- 10 files changed, 180 insertions(+), 74 deletions(-) diff --git a/cmd/twins/main.go b/cmd/twins/main.go index ca435d093a..6a483d9dd1 100644 --- a/cmd/twins/main.go +++ b/cmd/twins/main.go @@ -61,6 +61,7 @@ const ( defNatsURL = "nats://localhost:4222" defAuthURL = "localhost:8181" defAuthTimeout = "1s" + defOIDC = "false" envLogLevel = "MF_TWINS_LOG_LEVEL" envHTTPPort = "MF_TWINS_HTTP_PORT" @@ -81,6 +82,7 @@ const ( envNatsURL = "MF_NATS_URL" envAuthURL = "MF_AUTH_GRPC_URL" envAuthTimeout = "MF_AUTH_GRPC_TIMEOUT" + envOIDC = "MF_OIDC" ) type config struct { @@ -102,6 +104,7 @@ type config struct { authURL string authTimeout time.Duration + OIDC bool } func main() { @@ -169,6 +172,11 @@ func loadConfig() config { Port: mainflux.Env(envDBPort, defDBPort), } + oidc, err := strconv.ParseBool(mainflux.Env(envOIDC, defOIDC)) + if err != nil { + log.Fatalf("Invalid value passed for %s\n", envAuthTLS) + } + return config{ logLevel: mainflux.Env(envLogLevel, defLogLevel), httpPort: mainflux.Env(envHTTPPort, defHTTPPort), @@ -268,12 +276,15 @@ func newService(ps messaging.PubSub, chanID string, users mainflux.AuthServiceCl stateRepo := twmongodb.NewStateRepository(db) stateRepo = tracing.StateRepositoryMiddleware(dbTracer, stateRepo) + if c.OIDC { + logger.Info(("Using OIDC authentication")) + } idProvider := uuid.New() twinCache := rediscache.NewTwinCache(cacheClient) twinCache = tracing.TwinCacheMiddleware(cacheTracer, twinCache) - svc := twins.New(ps, users, twinRepo, twinCache, stateRepo, idProvider, chanID, logger) + svc := twins.New(ps, users, twinRepo, twinCache, stateRepo, idProvider, chanID, c.OIDC, logger) svc = api.LoggingMiddleware(svc, logger) svc = api.MetricsMiddleware( svc, diff --git a/cmd/users/main.go b/cmd/users/main.go index 5f7a6f1314..15974070c8 100644 --- a/cmd/users/main.go +++ b/cmd/users/main.go @@ -74,6 +74,8 @@ const ( defAuthURL = "localhost:8181" defAuthTimeout = "1s" + defOIDC = "false" + envLogLevel = "MF_USERS_LOG_LEVEL" envDBHost = "MF_USERS_DB_HOST" envDBPort = "MF_USERS_DB_PORT" @@ -109,6 +111,8 @@ const ( envAuthCACerts = "MF_AUTH_CA_CERTS" envAuthURL = "MF_AUTH_GRPC_URL" envAuthTimeout = "MF_AUTH_GRPC_TIMEOUT" + + envOIDC = "MF_OIDC" ) type config struct { @@ -127,6 +131,7 @@ type config struct { adminEmail string adminPassword string passRegex *regexp.Regexp + OIDC bool } func main() { @@ -179,6 +184,11 @@ func loadConfig() config { log.Fatalf("Invalid value passed for %s\n", envAuthTLS) } + oidc, err := strconv.ParseBool(mainflux.Env(envOIDC, defOIDC)) + if err != nil { + log.Fatalf("Invalid value passed for %s\n", envAuthTLS) + } + passRegex, err := regexp.Compile(mainflux.Env(envPassRegex, defPassRegex)) if err != nil { log.Fatalf("Invalid password validation rules %s\n", envPassRegex) @@ -222,6 +232,7 @@ func loadConfig() config { authTimeout: authTimeout, adminEmail: mainflux.Env(envAdminEmail, defAdminEmail), adminPassword: mainflux.Env(envAdminPassword, defAdminPassword), + OIDC: oidc, passRegex: passRegex, } @@ -293,10 +304,13 @@ func newService(db *sqlx.DB, tracer opentracing.Tracer, auth mainflux.AuthServic if err != nil { logger.Error(fmt.Sprintf("Failed to configure e-mailing util: %s", err.Error())) } + if c.OIDC { + logger.Info(("Using OIDC authentication")) + } idProvider := uuid.New() - svc := users.New(userRepo, hasher, auth, emailer, idProvider, c.passRegex) + svc := users.New(userRepo, hasher, auth, emailer, idProvider, c.OIDC, c.passRegex) svc = api.LoggingMiddleware(svc, logger) svc = api.MetricsMiddleware( svc, diff --git a/pkg/sdk/go/users_test.go b/pkg/sdk/go/users_test.go index e7688783d2..9ae4856d2e 100644 --- a/pkg/sdk/go/users_test.go +++ b/pkg/sdk/go/users_test.go @@ -37,7 +37,7 @@ func newUserService() users.Service { emailer := mocks.NewEmailer() idProvider := uuid.New() - return users.New(usersRepo, hasher, auth, emailer, idProvider, passRegex) + return users.New(usersRepo, hasher, auth, emailer, idProvider, false, passRegex) } func newUserServer(svc users.Service) *httptest.Server { diff --git a/readers/api/transport.go b/readers/api/transport.go index 4654e27819..2fd17b341b 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -50,12 +50,13 @@ var ( errChannelThingConnectionMissing = errors.New("channel is not connected to a thing") errNotChannelOwner = errors.New("user is not the owner of channel") auth mainflux.ThingsServiceClient + oidc bool ) // MakeHandler returns a HTTP handler for API endpoints. func MakeHandler(svc readers.MessageRepository, tc mainflux.ThingsServiceClient, svcName string) http.Handler { auth = tc - + oidc = true opts := []kithttp.ServerOption{ kithttp.ServerErrorEncoder(encodeError), } @@ -216,7 +217,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { } } -func authorize(r *http.Request, chanID string) error { +func authorize(r *http.Request, chanID string, oidc bool) error { token := r.Header.Get("Authorization") if token == "" { return errUnauthorizedAccess @@ -237,7 +238,7 @@ func authorize(r *http.Request, chanID string) error { return nil } - if u, err := identify(ctx, token); err == nil { + if u, err := identify(ctx, token, oidc); err == nil { _, err := auth.IsChannelOwner(ctx, &mainflux.ChannelOwnerReq{Owner: u.Id, ChanID: chanID}) if err != nil { e, ok := status.FromError(err) @@ -270,27 +271,31 @@ func readBoolValueQuery(r *http.Request, key string) (bool, error) { return b, nil } -func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { - if len(token) == 0 { - return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Empty authorization token")) - } - token = strings.ReplaceAll(token, "Bearer ", "") - - parsed, err := jwt.Parse(token, nil) - // if parsed == nil || !parsed.Valid { - // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) - // } - // TODO - Token should be properly validated - // to validate we need a public key - // it should be possible to get a public key from the token itself - if parsed == nil { - return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Invalid authorization token")) - } +func identify(ctx context.Context, token string, oidc bool) (u *mainflux.UserIdentity, err error) { + if oidc { + if len(token) == 0 { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Empty authorization token")) + } + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + // if parsed == nil || !parsed.Valid { + // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + // } + // TODO - Token should be properly validated + // to validate we need a public key + // it should be possible to get a public key from the token itself + if parsed == nil { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) - claims, _ := parsed.Claims.(jwt.MapClaims) + return &mainflux.UserIdentity{ + Id: claims["sub"].(string), + Email: claims["email"].(string), + }, nil + } - return &mainflux.UserIdentity{ - Id: claims["sub"].(string), - Email: claims["email"].(string), - }, nil + return nil, errors.New("Reading with user token implemented only in OIDC mode") } diff --git a/things/service.go b/things/service.go index 56fab46d0b..378bccc27e 100644 --- a/things/service.go +++ b/things/service.go @@ -166,25 +166,32 @@ func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err if len(token) == 0 { return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } - token = strings.ReplaceAll(token, "Bearer ", "") - parsed, err := jwt.Parse(token, nil) - // if parsed == nil || !parsed.Valid { - // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) - // } - // TODO - Token should be properly validated - // to validate we need a public key - // it should be possible to get a public key from the token itself - if parsed == nil { - return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) - } + if svc.oidc { + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + if err != nil || parsed == nil { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + } - claims, _ := parsed.Claims.(jwt.MapClaims) + claims, _ := parsed.Claims.(jwt.MapClaims) + id, ok := claims["sub"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) + } + email, ok := claims["email"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) + } + + return &mainflux.UserIdentity{ + Id: id, + Email: email, + }, nil + } - return &mainflux.UserIdentity{ - Id: claims["sub"].(string), - Email: claims["email"].(string), - }, nil + return ts.auth.Identify(ctx, &mainflux.Token{Value: token}) } func (ts *thingsService) CreateThings(ctx context.Context, token string, things ...Thing) ([]Thing, error) { diff --git a/twins/service.go b/twins/service.go index 839cea18fd..3e2d110289 100644 --- a/twins/service.go +++ b/twins/service.go @@ -8,8 +8,10 @@ import ( "encoding/json" "fmt" "math" + "strings" "time" + "github.com/golang-jwt/jwt/v4" "github.com/mainflux/mainflux/logger" "github.com/mainflux/mainflux/pkg/errors" "github.com/mainflux/mainflux/pkg/messaging" @@ -120,7 +122,7 @@ func (ts *twinsService) AddTwin(ctx context.Context, token string, twin Twin, de var b []byte defer ts.publish(&id, &err, crudOp["createSucc"], crudOp["createFail"], &b) - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return Twin{}, ErrUnauthorizedAccess } @@ -163,7 +165,7 @@ func (ts *twinsService) UpdateTwin(ctx context.Context, token string, twin Twin, var id string defer ts.publish(&id, &err, crudOp["updateSucc"], crudOp["updateFail"], &b) - _, err = ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return ErrUnauthorizedAccess } @@ -213,7 +215,7 @@ func (ts *twinsService) ViewTwin(ctx context.Context, token, twinID string) (tw var b []byte defer ts.publish(&twinID, &err, crudOp["getSucc"], crudOp["getFail"], &b) - _, err = ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return Twin{}, ErrUnauthorizedAccess } @@ -232,7 +234,7 @@ func (ts *twinsService) RemoveTwin(ctx context.Context, token, twinID string) (e var b []byte defer ts.publish(&twinID, &err, crudOp["removeSucc"], crudOp["removeFail"], &b) - _, err = ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return ErrUnauthorizedAccess } @@ -245,7 +247,7 @@ func (ts *twinsService) RemoveTwin(ctx context.Context, token, twinID string) (e } func (ts *twinsService) ListTwins(ctx context.Context, token string, offset uint64, limit uint64, name string, metadata Metadata) (Page, error) { - res, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + res, err := ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return Page{}, ErrUnauthorizedAccess } @@ -254,7 +256,7 @@ func (ts *twinsService) ListTwins(ctx context.Context, token string, offset uint } func (ts *twinsService) ListStates(ctx context.Context, token string, offset uint64, limit uint64, twinID string) (StatesPage, error) { - _, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}) + _, err := ts.identify(ctx, &mainflux.Token{Value: token}) if err != nil { return StatesPage{}, ErrUnauthorizedAccess } @@ -293,6 +295,38 @@ func (ts *twinsService) SaveStates(msg *messaging.Message) error { return nil } +func (ts *twinsService) identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + if len(token) == 0 { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) + } + + if svc.oidc { + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + if err != nil || parsed == nil { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) + id, ok := claims["sub"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) + } + email, ok := claims["email"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) + } + + return &mainflux.UserIdentity{ + Id: id, + Email: email, + }, nil + } + + return ts.auth.Identify(ctx, &mainflux.Token{Value: token}) +} + func (ts *twinsService) saveState(msg *messaging.Message, twinID string) error { var b []byte var err error diff --git a/users/api/endpoint_test.go b/users/api/endpoint_test.go index 777b21893c..4cd681aac1 100644 --- a/users/api/endpoint_test.go +++ b/users/api/endpoint_test.go @@ -78,7 +78,7 @@ func newService() users.Service { email := mocks.NewEmailer() idProvider := uuid.New() - return users.New(usersRepo, hasher, auth, email, idProvider, passRegex) + return users.New(usersRepo, hasher, auth, email, idProvider, false, passRegex) } func newServer(svc users.Service) *httptest.Server { diff --git a/users/postgres/init.go b/users/postgres/init.go index 34a15aabdf..821c802ac7 100644 --- a/users/postgres/init.go +++ b/users/postgres/init.go @@ -78,13 +78,6 @@ func migrateDB(db *sqlx.DB) error { `ALTER TABLE IF EXISTS users ADD PRIMARY KEY (id)`, }, }, - { - Id: "users_5", - Up: []string{ - `ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS users_owner_id_fkey`, - `ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS owner_id`, - }, - }, }, } diff --git a/users/service.go b/users/service.go index 28495a8ca3..63816447e7 100644 --- a/users/service.go +++ b/users/service.go @@ -6,7 +6,9 @@ package users import ( "context" "regexp" + "strings" + "github.com/golang-jwt/jwt/v4" "github.com/mainflux/mainflux" "github.com/mainflux/mainflux/auth" "github.com/mainflux/mainflux/pkg/errors" @@ -125,17 +127,19 @@ type usersService struct { users UserRepository hasher Hasher email Emailer + oidc bool auth mainflux.AuthServiceClient idProvider mainflux.IDProvider passRegex *regexp.Regexp } // New instantiates the users service implementation -func New(users UserRepository, hasher Hasher, auth mainflux.AuthServiceClient, e Emailer, idp mainflux.IDProvider, passRegex *regexp.Regexp) Service { +func New(users UserRepository, hasher Hasher, auth mainflux.AuthServiceClient, e Emailer, idp mainflux.IDProvider, oidc bool, passRegex *regexp.Regexp) Service { return &usersService{ users: users, hasher: hasher, auth: auth, + oidc: oidc, email: e, idProvider: idp, passRegex: passRegex, @@ -197,19 +201,19 @@ func (svc usersService) ViewUser(ctx context.Context, token, id string) (User, e } func (svc usersService) ViewProfile(ctx context.Context, token string) (User, error) { - email, err := svc.identify(ctx, token) + u, err := svc.identify(ctx, token) if err != nil { return User{}, err } - dbUser, err := svc.users.RetrieveByEmail(ctx, email) + dbUser, err := svc.users.RetrieveByID(ctx, u.ID) if err != nil { return User{}, errors.Wrap(ErrUnauthorizedAccess, err) } return User{ ID: dbUser.ID, - Email: email, + Email: u.Email, Password: "", Metadata: dbUser.Metadata, }, nil @@ -225,12 +229,12 @@ func (svc usersService) ListUsers(ctx context.Context, token string, offset, lim } func (svc usersService) UpdateUser(ctx context.Context, token string, u User) error { - email, err := svc.identify(ctx, token) + us, err := svc.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } user := User{ - Email: email, + Email: us.ID, Metadata: u.Metadata, } return svc.users.UpdateUser(ctx, user) @@ -249,11 +253,11 @@ func (svc usersService) GenerateResetToken(ctx context.Context, email, host stri } func (svc usersService) ResetPassword(ctx context.Context, resetToken, password string) error { - email, err := svc.identify(ctx, resetToken) + us, err := svc.identify(ctx, resetToken) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } - u, err := svc.users.RetrieveByEmail(ctx, email) + u, err := svc.users.RetrieveByID(ctx, us.ID) if err != nil || u.Email == "" { return ErrUserNotFound } @@ -264,11 +268,11 @@ func (svc usersService) ResetPassword(ctx context.Context, resetToken, password if err != nil { return err } - return svc.users.UpdatePassword(ctx, email, password) + return svc.users.UpdatePassword(ctx, us.Email, password) } func (svc usersService) ChangePassword(ctx context.Context, authToken, password, oldPassword string) error { - email, err := svc.identify(ctx, authToken) + us, err := svc.identify(ctx, authToken) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -276,13 +280,13 @@ func (svc usersService) ChangePassword(ctx context.Context, authToken, password, return ErrPasswordFormat } u := User{ - Email: email, + Email: us.Email, Password: oldPassword, } if _, err := svc.Login(ctx, u); err != nil { return ErrUnauthorizedAccess } - u, err = svc.users.RetrieveByEmail(ctx, email) + u, err = svc.users.RetrieveByEmail(ctx, us.Email) if err != nil || u.Email == "" { return ErrUserNotFound } @@ -291,7 +295,7 @@ func (svc usersService) ChangePassword(ctx context.Context, authToken, password, if err != nil { return err } - return svc.users.UpdatePassword(ctx, email, password) + return svc.users.UpdatePassword(ctx, us.Email, password) } func (svc usersService) SendPasswordReset(_ context.Context, host, email, token string) error { @@ -321,12 +325,50 @@ func (svc usersService) issue(ctx context.Context, id, email string, keyType uin return key.GetValue(), nil } -func (svc usersService) identify(ctx context.Context, token string) (string, error) { +func (svc usersService) identify(ctx context.Context, token string) (u User, err error) { + if svc.oidc { + if len(token) == 0 { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) + } + token = strings.ReplaceAll(token, "Bearer ", "") + + parsed, err := jwt.Parse(token, nil) + if err != nil || parsed == nil { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + } + + claims, _ := parsed.Claims.(jwt.MapClaims) + id, ok := claims["sub"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) + } + email, ok := claims["email"].(string) + if !ok { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) + } + user := User{ + ID: id, + Email: email, + } + + if _, err := svc.users.RetrieveByID(ctx, user.ID); err != nil { + if _, err = svc.users.Save(ctx, user); err != nil { + return User{}, err + } + } + + return user, nil + } + identity, err := svc.auth.Identify(ctx, &mainflux.Token{Value: token}) if err != nil { - return "", errors.Wrap(ErrUnauthorizedAccess, err) + return User{}, errors.Wrap(ErrUnauthorizedAccess, err) } - return identity.GetEmail(), nil + return User{ + ID: identity.GetId(), + Email: identity.GetEmail(), + }, nil + } func (svc usersService) members(ctx context.Context, token, groupID string, limit, offset uint64) ([]string, error) { diff --git a/users/service_test.go b/users/service_test.go index bcf6d25d49..919c3e1f3a 100644 --- a/users/service_test.go +++ b/users/service_test.go @@ -36,7 +36,7 @@ func newService() users.Service { auth := mocks.NewAuthService(map[string]string{user.Email: user.Email}) e := mocks.NewEmailer() - return users.New(userRepo, hasher, auth, e, idProvider, passRegex) + return users.New(userRepo, hasher, auth, e, idProvider, false, passRegex) } func TestRegister(t *testing.T) { From 20db37f596af6095006444cecf97408dcca27b25 Mon Sep 17 00:00:00 2001 From: mteodor Date: Sun, 17 Oct 2021 11:31:37 +0200 Subject: [PATCH 14/20] add oidc support for additional services Signed-off-by: mteodor --- cmd/things/main.go | 35 ++++++++++++++++++++++-------- readers/api/transport.go | 16 ++++++++++---- things/service.go | 46 +++++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/cmd/things/main.go b/cmd/things/main.go index 872da20a13..07c2b49760 100644 --- a/cmd/things/main.go +++ b/cmd/things/main.go @@ -70,6 +70,7 @@ const ( defJaegerURL = "" defAuthURL = "localhost:8181" defAuthTimeout = "1s" + defOIDC = "false" envLogLevel = "MF_THINGS_LOG_LEVEL" envDBHost = "MF_THINGS_DB_HOST" @@ -99,6 +100,7 @@ const ( envJaegerURL = "MF_JAEGER_URL" envAuthURL = "MF_AUTH_GRPC_URL" envAuthTimeout = "MF_AUTH_GRPC_TIMEOUT" + envOIDC = "MF_OIDC" ) type config struct { @@ -122,6 +124,7 @@ type config struct { jaegerURL string authURL string authTimeout time.Duration + OIDC bool } func main() { @@ -142,13 +145,17 @@ func main() { db := connectToDB(cfg.dbConfig, logger) defer db.Close() - // authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) - // defer authCloser.Close() + var auth mainflux.AuthServiceClient + var close func() error + if !cfg.OIDC { + authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) + defer authCloser.Close() - // auth, close := createAuthClient(cfg, authTracer, logger) - // if close != nil { - // defer close() - // } + auth, close = createAuthClient(cfg, authTracer, logger) + if close != nil { + defer close() + } + } dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) defer dbCloser.Close() @@ -156,7 +163,7 @@ func main() { cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) defer cacheCloser.Close() - svc := newService(nil, dbTracer, cacheTracer, db, cacheClient, esClient, logger) + svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, cfg.OIDC, logger) errs := make(chan error, 2) go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc), cfg.httpPort, cfg, logger, errs) @@ -184,6 +191,11 @@ func loadConfig() config { log.Fatalf("Invalid %s value: %s", envAuthTimeout, err.Error()) } + oidc, err := strconv.ParseBool(mainflux.Env(envOIDC, defOIDC)) + if err != nil { + log.Fatalf("Invalid value passed for %s\n", envClientTLS) + } + dbConfig := postgres.Config{ Host: mainflux.Env(envDBHost, defDBHost), Port: mainflux.Env(envDBPort, defDBPort), @@ -217,6 +229,7 @@ func loadConfig() config { jaegerURL: mainflux.Env(envJaegerURL, defJaegerURL), authURL: mainflux.Env(envAuthURL, defAuthURL), authTimeout: authTimeout, + OIDC: oidc, } } @@ -301,7 +314,7 @@ func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn { return conn } -func newService(auth mainflux.AuthServiceClient, dbTracer opentracing.Tracer, cacheTracer opentracing.Tracer, db *sqlx.DB, cacheClient *redis.Client, esClient *redis.Client, logger logger.Logger) things.Service { +func newService(auth mainflux.AuthServiceClient, dbTracer opentracing.Tracer, cacheTracer opentracing.Tracer, db *sqlx.DB, cacheClient *redis.Client, esClient *redis.Client, oidc bool, logger logger.Logger) things.Service { database := postgres.NewDatabase(db) thingsRepo := postgres.NewThingRepository(database) @@ -317,7 +330,11 @@ func newService(auth mainflux.AuthServiceClient, dbTracer opentracing.Tracer, ca thingCache = tracing.ThingCacheMiddleware(cacheTracer, thingCache) idProvider := uuid.New() - svc := things.New(auth, thingsRepo, channelsRepo, chanCache, thingCache, idProvider) + if oidc { + logger.Info(("Using OIDC authentication")) + } + + svc := things.New(auth, thingsRepo, channelsRepo, chanCache, thingCache, oidc, idProvider) svc = rediscache.NewEventStoreMiddleware(svc, esClient) svc = api.LoggingMiddleware(svc, logger) svc = api.MetricsMiddleware( diff --git a/readers/api/transport.go b/readers/api/transport.go index 2fd17b341b..75ec531a0c 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -81,7 +81,7 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) { return nil, errors.ErrInvalidQueryParams } - if err := authorize(r, chanID); err != nil { + if err := authorize(r, chanID, true); err != nil { return nil, err } @@ -285,15 +285,23 @@ func identify(ctx context.Context, token string, oidc bool) (u *mainflux.UserIde // TODO - Token should be properly validated // to validate we need a public key // it should be possible to get a public key from the token itself - if parsed == nil { + if parsed == nil || err != nil { return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Invalid authorization token")) } claims, _ := parsed.Claims.(jwt.MapClaims) + id, ok := claims["sub"].(string) + if !ok { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Missing claim sub")) + } + email, ok := claims["email"].(string) + if !ok { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Missing email in token")) + } return &mainflux.UserIdentity{ - Id: claims["sub"].(string), - Email: claims["email"].(string), + Id: id, + Email: email, }, nil } diff --git a/things/service.go b/things/service.go index 378bccc27e..aba2e4e60a 100644 --- a/things/service.go +++ b/things/service.go @@ -145,44 +145,46 @@ type thingsService struct { channels ChannelRepository channelCache ChannelCache thingCache ThingCache + OIDC bool idProvider mainflux.IDProvider ulidProvider mainflux.IDProvider } // New instantiates the things service implementation. -func New(auth mainflux.AuthServiceClient, things ThingRepository, channels ChannelRepository, ccache ChannelCache, tcache ThingCache, idp mainflux.IDProvider) Service { +func New(auth mainflux.AuthServiceClient, things ThingRepository, channels ChannelRepository, ccache ChannelCache, tcache ThingCache, oidc bool, idp mainflux.IDProvider) Service { return &thingsService{ auth: auth, things: things, channels: channels, channelCache: ccache, thingCache: tcache, + OIDC: oidc, idProvider: idp, ulidProvider: ulid.New(), } } -func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { +func (ts *thingsService) identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { if len(token) == 0 { return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } - if svc.oidc { + if ts.OIDC { token = strings.ReplaceAll(token, "Bearer ", "") parsed, err := jwt.Parse(token, nil) if err != nil || parsed == nil { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) } claims, _ := parsed.Claims.(jwt.MapClaims) id, ok := claims["sub"].(string) if !ok { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) } email, ok := claims["email"].(string) if !ok { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) } return &mainflux.UserIdentity{ @@ -195,7 +197,7 @@ func identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err } func (ts *thingsService) CreateThings(ctx context.Context, token string, things ...Thing) ([]Thing, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return []Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -220,7 +222,7 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things } func (ts *thingsService) UpdateThing(ctx context.Context, token string, thing Thing) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -231,7 +233,7 @@ func (ts *thingsService) UpdateThing(ctx context.Context, token string, thing Th } func (ts *thingsService) UpdateKey(ctx context.Context, token, id, key string) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -242,7 +244,7 @@ func (ts *thingsService) UpdateKey(ctx context.Context, token, id, key string) e } func (ts *thingsService) ViewThing(ctx context.Context, token, id string) (Thing, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return Thing{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -251,7 +253,7 @@ func (ts *thingsService) ViewThing(ctx context.Context, token, id string) (Thing } func (ts *thingsService) ListThings(ctx context.Context, token string, pm PageMetadata) (Page, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -260,7 +262,7 @@ func (ts *thingsService) ListThings(ctx context.Context, token string, pm PageMe } func (ts *thingsService) ListThingsByChannel(ctx context.Context, token, chID string, pm PageMetadata) (Page, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -269,7 +271,7 @@ func (ts *thingsService) ListThingsByChannel(ctx context.Context, token, chID st } func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -281,7 +283,7 @@ func (ts *thingsService) RemoveThing(ctx context.Context, token, id string) erro } func (ts *thingsService) CreateChannels(ctx context.Context, token string, channels ...Channel) ([]Channel, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return []Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -299,7 +301,7 @@ func (ts *thingsService) CreateChannels(ctx context.Context, token string, chann } func (ts *thingsService) UpdateChannel(ctx context.Context, token string, channel Channel) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -309,7 +311,7 @@ func (ts *thingsService) UpdateChannel(ctx context.Context, token string, channe } func (ts *thingsService) ViewChannel(ctx context.Context, token, id string) (Channel, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return Channel{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -318,7 +320,7 @@ func (ts *thingsService) ViewChannel(ctx context.Context, token, id string) (Cha } func (ts *thingsService) ListChannels(ctx context.Context, token string, pm PageMetadata) (ChannelsPage, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -327,7 +329,7 @@ func (ts *thingsService) ListChannels(ctx context.Context, token string, pm Page } func (ts *thingsService) ListChannelsByThing(ctx context.Context, token, thID string, pm PageMetadata) (ChannelsPage, error) { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return ChannelsPage{}, errors.Wrap(ErrUnauthorizedAccess, err) } @@ -336,7 +338,7 @@ func (ts *thingsService) ListChannelsByThing(ctx context.Context, token, thID st } func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -349,7 +351,7 @@ func (ts *thingsService) RemoveChannel(ctx context.Context, token, id string) er } func (ts *thingsService) Connect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -358,7 +360,7 @@ func (ts *thingsService) Connect(ctx context.Context, token string, chIDs, thIDs } func (ts *thingsService) Disconnect(ctx context.Context, token string, chIDs, thIDs []string) error { - res, err := identify(ctx, token) + res, err := ts.identify(ctx, token) if err != nil { return errors.Wrap(ErrUnauthorizedAccess, err) } @@ -446,7 +448,7 @@ func (ts *thingsService) hasThing(ctx context.Context, chanID, thingKey string) } func (ts *thingsService) ListMembers(ctx context.Context, token, groupID string, pm PageMetadata) (Page, error) { - if _, err := ts.auth.Identify(ctx, &mainflux.Token{Value: token}); err != nil { + if _, err := ts.identify(ctx, token); err != nil { return Page{}, errors.Wrap(ErrUnauthorizedAccess, err) } From 4046eeb87cd57a03abeccabe666417ff3bc91f73 Mon Sep 17 00:00:00 2001 From: mteodor Date: Tue, 19 Oct 2021 11:22:27 +0200 Subject: [PATCH 15/20] add oidc mode env var Signed-off-by: mteodor --- cmd/things/main.go | 14 +++++++------- cmd/twins/main.go | 27 +++++++++++++++++++-------- readers/api/transport.go | 25 +++++++++++++++++-------- things/service.go | 10 ++++++---- users/service.go | 16 ++++++++++------ 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/cmd/things/main.go b/cmd/things/main.go index 07c2b49760..e6adfdefaf 100644 --- a/cmd/things/main.go +++ b/cmd/things/main.go @@ -145,6 +145,12 @@ func main() { db := connectToDB(cfg.dbConfig, logger) defer db.Close() + dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) + defer dbCloser.Close() + + cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) + defer cacheCloser.Close() + var auth mainflux.AuthServiceClient var close func() error if !cfg.OIDC { @@ -157,12 +163,6 @@ func main() { } } - dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) - defer dbCloser.Close() - - cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) - defer cacheCloser.Close() - svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, cfg.OIDC, logger) errs := make(chan error, 2) @@ -310,7 +310,7 @@ func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn { logger.Error(fmt.Sprintf("Failed to connect to auth service: %s", err)) os.Exit(1) } - + logger.Info(fmt.Sprint("Connected to auth service %s", cfg.authURL)) return conn } diff --git a/cmd/twins/main.go b/cmd/twins/main.go index 6a483d9dd1..b6fe1bd1d1 100644 --- a/cmd/twins/main.go +++ b/cmd/twins/main.go @@ -127,9 +127,17 @@ func main() { dbTracer, dbCloser := initJaeger("twins_db", cfg.jaegerURL, logger) defer dbCloser.Close() - authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) - defer authCloser.Close() - auth, _ := createAuthClient(cfg, authTracer, logger) + var auth mainflux.AuthServiceClient + var close func() error + if !cfg.OIDC { + authTracer, authCloser := initJaeger("auth", cfg.jaegerURL, logger) + defer authCloser.Close() + + auth, close = createAuthClient(cfg, authTracer, logger) + if close != nil { + defer close() + } + } pubSub, err := nats.NewPubSub(cfg.natsURL, queue, logger) if err != nil { @@ -138,7 +146,7 @@ func main() { } defer pubSub.Close() - svc := newService(pubSub, cfg.channelID, auth, dbTracer, db, cacheTracer, cacheClient, logger) + svc := newService(pubSub, cfg.channelID, auth, dbTracer, db, cacheTracer, cacheClient, cfg.OIDC, logger) tracer, closer := initJaeger("twins", cfg.jaegerURL, logger) defer closer.Close() @@ -174,7 +182,7 @@ func loadConfig() config { oidc, err := strconv.ParseBool(mainflux.Env(envOIDC, defOIDC)) if err != nil { - log.Fatalf("Invalid value passed for %s\n", envAuthTLS) + log.Fatalf("Invalid value passed for %s\n", envOIDC) } return config{ @@ -195,6 +203,7 @@ func loadConfig() config { natsURL: mainflux.Env(envNatsURL, defNatsURL), authURL: mainflux.Env(envAuthURL, defAuthURL), authTimeout: authTimeout, + OIDC: oidc, } } @@ -253,6 +262,8 @@ func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn { os.Exit(1) } + logger.Info(fmt.Sprint("Connected to auth service %s", cfg.authURL)) + return conn } @@ -270,13 +281,13 @@ func connectToRedis(cacheURL, cachePass, cacheDB string, logger logger.Logger) * }) } -func newService(ps messaging.PubSub, chanID string, users mainflux.AuthServiceClient, dbTracer opentracing.Tracer, db *mongo.Database, cacheTracer opentracing.Tracer, cacheClient *redis.Client, logger logger.Logger) twins.Service { +func newService(ps messaging.PubSub, chanID string, users mainflux.AuthServiceClient, dbTracer opentracing.Tracer, db *mongo.Database, cacheTracer opentracing.Tracer, cacheClient *redis.Client, oidc bool, logger logger.Logger) twins.Service { twinRepo := twmongodb.NewTwinRepository(db) twinRepo = tracing.TwinRepositoryMiddleware(dbTracer, twinRepo) stateRepo := twmongodb.NewStateRepository(db) stateRepo = tracing.StateRepositoryMiddleware(dbTracer, stateRepo) - if c.OIDC { + if oidc { logger.Info(("Using OIDC authentication")) } @@ -284,7 +295,7 @@ func newService(ps messaging.PubSub, chanID string, users mainflux.AuthServiceCl twinCache := rediscache.NewTwinCache(cacheClient) twinCache = tracing.TwinCacheMiddleware(cacheTracer, twinCache) - svc := twins.New(ps, users, twinRepo, twinCache, stateRepo, idProvider, chanID, c.OIDC, logger) + svc := twins.New(ps, users, twinRepo, twinCache, stateRepo, idProvider, chanID, oidc, logger) svc = api.LoggingMiddleware(svc, logger) svc = api.MetricsMiddleware( svc, diff --git a/readers/api/transport.go b/readers/api/transport.go index 75ec531a0c..9314893338 100644 --- a/readers/api/transport.go +++ b/readers/api/transport.go @@ -6,6 +6,7 @@ package api import ( "context" "encoding/json" + "fmt" "net/http" "strconv" "strings" @@ -222,19 +223,23 @@ func authorize(r *http.Request, chanID string, oidc bool) error { if token == "" { return errUnauthorizedAccess } + fmt.Println("authorize reader") ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() if _, err := uuid.FromString(token); err == nil { - _, err := auth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: chanID}) + thingID, err := auth.CanAccessByKey(ctx, &mainflux.AccessByKeyReq{Token: token, ChanID: chanID}) if err != nil { e, ok := status.FromError(err) if ok && e.Code() == codes.PermissionDenied { + fmt.Println("authorize reader") return errors.Wrap(errUnauthorizedAccess, errChannelThingConnectionMissing) } + fmt.Printf("thing id %v no access on %v - %v\n", thingID, chanID, err) return err } + fmt.Printf("thing id %v access on %v \n", thingID, chanID) return nil } @@ -272,20 +277,23 @@ func readBoolValueQuery(r *http.Request, key string) (bool, error) { } func identify(ctx context.Context, token string, oidc bool) (u *mainflux.UserIdentity, err error) { + fmt.Printf("identify using token %v\n", oidc) + token = strings.ReplaceAll(token, "Bearer ", "") + if len(token) == 0 { + return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Empty authorization token")) + } if oidc { - if len(token) == 0 { - return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Empty authorization token")) - } - token = strings.ReplaceAll(token, "Bearer ", "") - - parsed, err := jwt.Parse(token, nil) // if parsed == nil || !parsed.Valid { // return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) // } // TODO - Token should be properly validated // to validate we need a public key // it should be possible to get a public key from the token itself - if parsed == nil || err != nil { + parsed, err := jwt.Parse(token, nil) + if err != nil { + fmt.Println(err) + } + if parsed == nil { return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Invalid authorization token")) } @@ -298,6 +306,7 @@ func identify(ctx context.Context, token string, oidc bool) (u *mainflux.UserIde if !ok { return nil, errors.Wrap(errUnauthorizedAccess, errors.New("Missing email in token")) } + fmt.Printf("User %v, with email %v\n", id, email) return &mainflux.UserIdentity{ Id: id, diff --git a/things/service.go b/things/service.go index aba2e4e60a..671f026afa 100644 --- a/things/service.go +++ b/things/service.go @@ -5,6 +5,7 @@ package things import ( "context" + "fmt" "strings" "github.com/golang-jwt/jwt/v4" @@ -165,15 +166,16 @@ func New(auth mainflux.AuthServiceClient, things ThingRepository, channels Chann } func (ts *thingsService) identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + token = strings.ReplaceAll(token, "Bearer ", "") if len(token) == 0 { return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } - if ts.OIDC { - token = strings.ReplaceAll(token, "Bearer ", "") - parsed, err := jwt.Parse(token, nil) - if err != nil || parsed == nil { + if err != nil { + fmt.Println(err) + } + if parsed == nil { return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) } diff --git a/users/service.go b/users/service.go index 63816447e7..43692f2c3a 100644 --- a/users/service.go +++ b/users/service.go @@ -5,6 +5,7 @@ package users import ( "context" + "fmt" "regexp" "strings" @@ -326,14 +327,17 @@ func (svc usersService) issue(ctx context.Context, id, email string, keyType uin } func (svc usersService) identify(ctx context.Context, token string) (u User, err error) { - if svc.oidc { - if len(token) == 0 { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) - } - token = strings.ReplaceAll(token, "Bearer ", "") + token = strings.ReplaceAll(token, "Bearer ", "") + if len(token) == 0 { + return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) + } + if svc.oidc { parsed, err := jwt.Parse(token, nil) - if err != nil || parsed == nil { + if err != nil { + fmt.Println(err) + } + if parsed == nil { return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) } From c90af57b6590f52648e0a686fc649b3be1ecddeb Mon Sep 17 00:00:00 2001 From: mteodor Date: Tue, 19 Oct 2021 11:22:37 +0200 Subject: [PATCH 16/20] add oidc mode env var Signed-off-by: mteodor --- twins/service.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/twins/service.go b/twins/service.go index 3e2d110289..03d7e22cf2 100644 --- a/twins/service.go +++ b/twins/service.go @@ -99,12 +99,13 @@ type twinsService struct { channelID string twinCache TwinCache logger logger.Logger + OIDC bool } var _ Service = (*twinsService)(nil) // New instantiates the twins service implementation. -func New(publisher messaging.Publisher, auth mainflux.AuthServiceClient, twins TwinRepository, tcache TwinCache, sr StateRepository, idp mainflux.IDProvider, chann string, logger logger.Logger) Service { +func New(publisher messaging.Publisher, auth mainflux.AuthServiceClient, twins TwinRepository, tcache TwinCache, sr StateRepository, idp mainflux.IDProvider, chann string, oidc bool, logger logger.Logger) Service { return &twinsService{ publisher: publisher, auth: auth, @@ -114,6 +115,7 @@ func New(publisher messaging.Publisher, auth mainflux.AuthServiceClient, twins T idProvider: idp, channelID: chann, logger: logger, + OIDC: oidc, } } @@ -122,7 +124,7 @@ func (ts *twinsService) AddTwin(ctx context.Context, token string, twin Twin, de var b []byte defer ts.publish(&id, &err, crudOp["createSucc"], crudOp["createFail"], &b) - res, err := ts.identify(ctx, &mainflux.Token{Value: token}) + res, err := ts.identify(ctx, token) if err != nil { return Twin{}, ErrUnauthorizedAccess } @@ -165,7 +167,7 @@ func (ts *twinsService) UpdateTwin(ctx context.Context, token string, twin Twin, var id string defer ts.publish(&id, &err, crudOp["updateSucc"], crudOp["updateFail"], &b) - _, err = ts.identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, token) if err != nil { return ErrUnauthorizedAccess } @@ -215,7 +217,7 @@ func (ts *twinsService) ViewTwin(ctx context.Context, token, twinID string) (tw var b []byte defer ts.publish(&twinID, &err, crudOp["getSucc"], crudOp["getFail"], &b) - _, err = ts.identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, token) if err != nil { return Twin{}, ErrUnauthorizedAccess } @@ -234,7 +236,7 @@ func (ts *twinsService) RemoveTwin(ctx context.Context, token, twinID string) (e var b []byte defer ts.publish(&twinID, &err, crudOp["removeSucc"], crudOp["removeFail"], &b) - _, err = ts.identify(ctx, &mainflux.Token{Value: token}) + _, err = ts.identify(ctx, token) if err != nil { return ErrUnauthorizedAccess } @@ -247,7 +249,7 @@ func (ts *twinsService) RemoveTwin(ctx context.Context, token, twinID string) (e } func (ts *twinsService) ListTwins(ctx context.Context, token string, offset uint64, limit uint64, name string, metadata Metadata) (Page, error) { - res, err := ts.identify(ctx, &mainflux.Token{Value: token}) + res, err := ts.identify(ctx, token) if err != nil { return Page{}, ErrUnauthorizedAccess } @@ -256,7 +258,7 @@ func (ts *twinsService) ListTwins(ctx context.Context, token string, offset uint } func (ts *twinsService) ListStates(ctx context.Context, token string, offset uint64, limit uint64, twinID string) (StatesPage, error) { - _, err := ts.identify(ctx, &mainflux.Token{Value: token}) + _, err := ts.identify(ctx, token) if err != nil { return StatesPage{}, ErrUnauthorizedAccess } @@ -296,26 +298,27 @@ func (ts *twinsService) SaveStates(msg *messaging.Message) error { } func (ts *twinsService) identify(ctx context.Context, token string) (u *mainflux.UserIdentity, err error) { + token = strings.ReplaceAll(token, "Bearer ", "") if len(token) == 0 { return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Empty authorization token")) } - if svc.oidc { - token = strings.ReplaceAll(token, "Bearer ", "") - + if ts.OIDC { parsed, err := jwt.Parse(token, nil) - if err != nil || parsed == nil { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) + if err != nil { + fmt.Println(err) + } + if parsed == nil { + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Invalid authorization token")) } - claims, _ := parsed.Claims.(jwt.MapClaims) id, ok := claims["sub"].(string) if !ok { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing claim sub")) } email, ok := claims["email"].(string) if !ok { - return User{}, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) + return nil, errors.Wrap(ErrUnauthorizedAccess, errors.New("Missing email in token")) } return &mainflux.UserIdentity{ From 98060f8c8241ac47411cb6a65b153a43f6aa65af Mon Sep 17 00:00:00 2001 From: mteodor Date: Wed, 20 Oct 2021 10:37:56 +0200 Subject: [PATCH 17/20] move code Signed-off-by: mteodor --- cmd/things/main.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/things/main.go b/cmd/things/main.go index e6adfdefaf..df9e95b6c1 100644 --- a/cmd/things/main.go +++ b/cmd/things/main.go @@ -145,12 +145,6 @@ func main() { db := connectToDB(cfg.dbConfig, logger) defer db.Close() - dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) - defer dbCloser.Close() - - cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) - defer cacheCloser.Close() - var auth mainflux.AuthServiceClient var close func() error if !cfg.OIDC { @@ -163,6 +157,12 @@ func main() { } } + dbTracer, dbCloser := initJaeger("things_db", cfg.jaegerURL, logger) + defer dbCloser.Close() + + cacheTracer, cacheCloser := initJaeger("things_cache", cfg.jaegerURL, logger) + defer cacheCloser.Close() + svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, cfg.OIDC, logger) errs := make(chan error, 2) From 63bd05c5100a96e50323ee49065e86df726deefb Mon Sep 17 00:00:00 2001 From: mteodor Date: Wed, 20 Oct 2021 10:52:42 +0200 Subject: [PATCH 18/20] revert to default value Signed-off-by: mteodor --- docker/.env | 2 +- docker/addons/bootstrap/docker-compose.yml | 1 + docker/addons/cassandra-reader/docker-compose.yml | 1 + docker/addons/influxdb-reader/docker-compose.yml | 1 + docker/addons/mongodb-reader/docker-compose.yml | 1 + docker/addons/postgres-reader/docker-compose.yml | 1 + docker/docker-compose.yml | 3 +++ 7 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docker/.env b/docker/.env index e091d15100..3d681d44a9 100644 --- a/docker/.env +++ b/docker/.env @@ -236,7 +236,7 @@ MF_MONGO_WRITER_PORT=8901 MF_MONGO_WRITER_DB=mainflux MF_MONGO_WRITER_DB_PORT=27017 MF_MONGO_WRITER_CONTENT_TYPE=application/senml+json -MF_MONGO_WRITER_TRANSFORMER=json +MF_MONGO_WRITER_TRANSFORMER=senml ### MongoDB Reader MF_MONGO_READER_LOG_LEVEL=debug diff --git a/docker/addons/bootstrap/docker-compose.yml b/docker/addons/bootstrap/docker-compose.yml index f117c38db7..c014d7d360 100644 --- a/docker/addons/bootstrap/docker-compose.yml +++ b/docker/addons/bootstrap/docker-compose.yml @@ -52,5 +52,6 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_AUTH_GRPC_URL: ${MF_AUTH_GRPC_URL} MF_AUTH_GRPC_TIMMEOUT: ${MF_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} networks: - docker_mainflux-base-net diff --git a/docker/addons/cassandra-reader/docker-compose.yml b/docker/addons/cassandra-reader/docker-compose.yml index eeea67b015..5acef1ade3 100644 --- a/docker/addons/cassandra-reader/docker-compose.yml +++ b/docker/addons/cassandra-reader/docker-compose.yml @@ -27,6 +27,7 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_THINGS_AUTH_GRPC_URL: ${MF_THINGS_AUTH_GRPC_URL} MF_THINGS_AUTH_GRPC_TIMEOUT: ${MF_THINGS_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} ports: - ${MF_CASSANDRA_READER_PORT}:${MF_CASSANDRA_READER_PORT} networks: diff --git a/docker/addons/influxdb-reader/docker-compose.yml b/docker/addons/influxdb-reader/docker-compose.yml index 25ccd6fffb..d047488f94 100644 --- a/docker/addons/influxdb-reader/docker-compose.yml +++ b/docker/addons/influxdb-reader/docker-compose.yml @@ -32,6 +32,7 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_THINGS_AUTH_GRPC_URL: ${MF_THINGS_AUTH_GRPC_URL} MF_THINGS_AUTH_GRPC_TIMEOUT: ${MF_THINGS_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} ports: - ${MF_INFLUX_READER_PORT}:${MF_INFLUX_READER_PORT} networks: diff --git a/docker/addons/mongodb-reader/docker-compose.yml b/docker/addons/mongodb-reader/docker-compose.yml index ec14081240..45f9d876b6 100644 --- a/docker/addons/mongodb-reader/docker-compose.yml +++ b/docker/addons/mongodb-reader/docker-compose.yml @@ -29,6 +29,7 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_THINGS_AUTH_GRPC_URL: ${MF_THINGS_AUTH_GRPC_URL} MF_THINGS_AUTH_GRPC_TIMEOUT: ${MF_THINGS_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} ports: - ${MF_MONGO_READER_PORT}:${MF_MONGO_READER_PORT} networks: diff --git a/docker/addons/postgres-reader/docker-compose.yml b/docker/addons/postgres-reader/docker-compose.yml index b4a2f52123..1c86e100c9 100644 --- a/docker/addons/postgres-reader/docker-compose.yml +++ b/docker/addons/postgres-reader/docker-compose.yml @@ -35,6 +35,7 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_THINGS_AUTH_GRPC_URL: ${MF_THINGS_AUTH_GRPC_URL} MF_THINGS_AUTH_GRPC_TIMEOUT: ${MF_THINGS_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} ports: - ${MF_POSTGRES_READER_PORT}:${MF_POSTGRES_READER_PORT} networks: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index a2034a6ccc..97167ab07a 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -87,6 +87,7 @@ services: MF_AUTH_GRPC_PORT: ${MF_AUTH_GRPC_PORT} MF_AUTH_SECRET: ${MF_AUTH_SECRET} MF_JAEGER_URL: ${MF_JAEGER_URL} + MF_OIDC: ${MF_OIDC} ports: - ${MF_AUTH_HTTP_PORT}:${MF_AUTH_HTTP_PORT} - ${MF_AUTH_GRPC_PORT}:${MF_AUTH_GRPC_PORT} @@ -136,6 +137,7 @@ services: MF_AUTH_GRPC_TIMEOUT: ${MF_AUTH_GRPC_TIMEOUT} MF_USERS_ADMIN_EMAIL: ${MF_USERS_ADMIN_EMAIL} MF_USERS_ADMIN_PASSWORD: ${MF_USERS_ADMIN_PASSWORD} + MF_OIDC: ${MF_OIDC} ports: - ${MF_USERS_HTTP_PORT}:${MF_USERS_HTTP_PORT} networks: @@ -185,6 +187,7 @@ services: MF_JAEGER_URL: ${MF_JAEGER_URL} MF_AUTH_GRPC_URL: ${MF_AUTH_GRPC_URL} MF_AUTH_GRPC_TIMEOUT: ${MF_AUTH_GRPC_TIMEOUT} + MF_OIDC: ${MF_OIDC} ports: - ${MF_THINGS_HTTP_PORT}:${MF_THINGS_HTTP_PORT} - ${MF_THINGS_AUTH_HTTP_PORT}:${MF_THINGS_AUTH_HTTP_PORT} From d4fbb26d6a470e9765112578405ee4bc328754ca Mon Sep 17 00:00:00 2001 From: Mirko Teodorovic Date: Tue, 15 Dec 2020 11:35:53 +0100 Subject: [PATCH 19/20] remove owner id Signed-off-by: Mirko Teodorovic --- users/postgres/init.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/users/postgres/init.go b/users/postgres/init.go index 821c802ac7..34a15aabdf 100644 --- a/users/postgres/init.go +++ b/users/postgres/init.go @@ -78,6 +78,13 @@ func migrateDB(db *sqlx.DB) error { `ALTER TABLE IF EXISTS users ADD PRIMARY KEY (id)`, }, }, + { + Id: "users_5", + Up: []string{ + `ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS users_owner_id_fkey`, + `ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS owner_id`, + }, + }, }, } From 8a946dfb0f4c6c2976750ff035617d6d2a63026b Mon Sep 17 00:00:00 2001 From: mteodor Date: Fri, 13 Aug 2021 12:23:13 +0200 Subject: [PATCH 20/20] revert init.go Signed-off-by: mteodor --- users/postgres/init.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/users/postgres/init.go b/users/postgres/init.go index 34a15aabdf..821c802ac7 100644 --- a/users/postgres/init.go +++ b/users/postgres/init.go @@ -78,13 +78,6 @@ func migrateDB(db *sqlx.DB) error { `ALTER TABLE IF EXISTS users ADD PRIMARY KEY (id)`, }, }, - { - Id: "users_5", - Up: []string{ - `ALTER TABLE IF EXISTS users DROP CONSTRAINT IF EXISTS users_owner_id_fkey`, - `ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS owner_id`, - }, - }, }, }