graph(oidc): Consume UserSignedIn events in graph service

Pass them to the identity backend to update the last sign-in date of the user.
This commit is contained in:
Ralf Haferkamp
2024-09-17 16:02:47 +02:00
committed by Ralf Haferkamp
parent cb8934081f
commit 8e158d52bb
10 changed files with 158 additions and 12 deletions
+1 -6
View File
@@ -13,7 +13,6 @@ import (
"github.com/go-chi/chi/v5"
"github.com/jellydator/ttlcache/v3"
"go-micro.dev/v4/client"
mevents "go-micro.dev/v4/events"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/types/known/emptypb"
@@ -28,11 +27,6 @@ import (
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
)
// Publisher is the interface for events publisher
type Publisher interface {
Publish(string, interface{}, ...mevents.PublishOption) error
}
// Permissions is the interface used to access the permissions service
type Permissions interface {
ListPermissions(ctx context.Context, req *settingssvc.ListPermissionsRequest, opts ...client.CallOption) (*settingssvc.ListPermissionsResponse, error)
@@ -68,6 +62,7 @@ type Graph struct {
valueService settingssvc.ValueService
specialDriveItemsCache *ttlcache.Cache[string, interface{}]
eventsPublisher events.Publisher
eventsConsumer events.Consumer
searchService searchsvc.SearchProviderService
keycloakClient keycloak.Client
historyClient ehsvc.EventHistoryService
+17
View File
@@ -1,6 +1,7 @@
package svc
import (
"context"
"net/http"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -22,6 +23,7 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Context context.Context
Logger log.Logger
Config *config.Config
Middleware []func(http.Handler) http.Handler
@@ -34,6 +36,7 @@ type Options struct {
ValueService settingssvc.ValueService
RoleManager *roles.Manager
EventsPublisher events.Publisher
EventsConsumer events.Consumer
SearchService searchsvc.SearchProviderService
KeycloakClient keycloak.Client
EventHistoryClient ehsvc.EventHistoryService
@@ -51,6 +54,13 @@ func newOptions(opts ...Option) Options {
return opt
}
// Context provides a function to set the context option.
func Context(ctx context.Context) Option {
return func(o *Options) {
o.Context = ctx
}
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
@@ -142,6 +152,13 @@ func EventsPublisher(val events.Publisher) Option {
}
}
// EventsConsumer provides a function to set the EventsConsumer option.
func EventsConsumer(val events.Consumer) Option {
return func(o *Options) {
o.EventsConsumer = val
}
}
// KeycloakClient provides a function to set the KeycloakCient option.
func KeycloakClient(val keycloak.Client) Option {
return func(o *Options) {
+38
View File
@@ -1,6 +1,7 @@
package svc
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
@@ -16,10 +17,13 @@ import (
"github.com/jellydator/ttlcache/v3"
microstore "go-micro.dev/v4/store"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/store"
"github.com/cs3org/reva/v2/pkg/utils"
ocisldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/ocis-pkg/roles"
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
@@ -148,6 +152,7 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
mux: m,
specialDriveItemsCache: spacePropertiesCache,
eventsPublisher: options.EventsPublisher,
eventsConsumer: options.EventsConsumer,
searchService: options.SearchService,
identityEducationBackend: options.IdentityEducationBackend,
keycloakClient: options.KeycloakClient,
@@ -515,6 +520,39 @@ func setIdentityBackends(options Options, svc *Graph) error {
svc.identityBackend = options.IdentityBackend
}
return svc.StartListenForLogonEvents(options.Context, options.Logger)
}
func (g *Graph) StartListenForLogonEvents(ctx context.Context, l log.Logger) error {
if g.eventsConsumer == nil {
return nil
}
var _registeredEvents = []events.Unmarshaller{
events.UserSignedIn{},
}
evChannel, err := events.Consume(g.eventsConsumer, "graph", _registeredEvents...)
if err != nil {
l.Error().Err(err).Msg("cannot consume from nats")
return err
}
go func() {
for loop := true; loop; {
select {
case e := <-evChannel:
switch ev := e.Event.(type) {
default:
l.Error().Interface("event", e).Msg("unhandled event")
case events.UserSignedIn:
if err := g.identityBackend.UpdateLastSignInDate(ctx, ev.Executant.OpaqueId, utils.TSToTime(ev.Timestamp)); err != nil {
l.Error().Err(err).Str("userid", ev.Executant.OpaqueId).Msg("Error updating last sign in date")
}
}
case <-ctx.Done():
l.Info().Msg("context cancelled")
loop = false
}
}
}()
return nil
}