Integrate keycloak and events data into graph.

This PR adds the data from keycloak and events into the GDPR export of
the graph service.
This commit is contained in:
Daniël Franke
2023-04-05 12:39:05 +02:00
committed by jkoberg
parent 562c18b84b
commit 8e32b4f5da
7 changed files with 68 additions and 10 deletions

View File

@@ -30,7 +30,8 @@ type Config struct {
Identity Identity `yaml:"identity"`
Events Events `yaml:"events"`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;USERLOG_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services."`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;USERLOG_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services."`
Keycloak Keycloak `yaml:"keycloak"`
Context context.Context `yaml:"-"`
}
@@ -121,3 +122,13 @@ type CORS struct {
AllowedHeaders []string `yaml:"allow_headers" env:"OCIS_CORS_ALLOW_HEADERS;GRAPH_CORS_ALLOW_HEADERS" desc:"A comma-separated list of allowed CORS headers. See following chapter for more details: *Access-Control-Request-Headers* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers."`
AllowCredentials bool `yaml:"allow_credentials" env:"OCIS_CORS_ALLOW_CREDENTIALS;GRAPH_CORS_ALLOW_CREDENTIALS" desc:"Allow credentials for CORS.See following chapter for more details: *Access-Control-Allow-Credentials* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials."`
}
// Keycloak configuration
type Keycloak struct {
BasePath string `yaml:"base_path" env:"KEYCLOAK_BASE_PATH;GRAPH_KEYCLOAK_BASE_PATH" desc:"The URL to access keycloak."`
ClientID string `yaml:"client_id" env:"KEYCLOAK_CLIENT_ID;GRAPH_KEYCLOAK_CLIENT_ID" desc:"The client id to authenticate with keycloak."`
ClientSecret string `yaml:"client_secret" env:"KEYCLOAK_CLIENT_SECRET;GRAPH_KEYCLOAK_CLIENT_SECRET" desc:"The client secret to use in authentication."`
ClientRealm string `yaml:"client_realm" env:"KEYCLOAK_CLIENT_REALM;GRAPH_KEYCLOAK_CLIENT_REALM" desc:"The realm the client is defined in."`
UserRealm string `yaml:"user_realm" env:"KEYCLOAK_USER_REALM;GRAPH_KEYCLOAK_USER_REALM" desc:"The realm users are defined."`
InsecureSkipVerify bool `yaml:"insecure_skip_verify" env:"KEYCLOAK_INSECURE_SKIP_VERIFY;GRAPH_KEYCLOAK_INSECURE_SKIP_VERIFY" desc:"Disable TLS certificate validation for Keycloak connections. Do not set this in production environments."`
}

View File

@@ -15,10 +15,13 @@ import (
"github.com/owncloud/ocis/v2/ocis-pkg/account"
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
ociscrypto "github.com/owncloud/ocis/v2/ocis-pkg/crypto"
"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
"github.com/owncloud/ocis/v2/ocis-pkg/version"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
graphMiddleware "github.com/owncloud/ocis/v2/services/graph/pkg/middleware"
@@ -132,6 +135,18 @@ func Server(opts ...Option) (http.Service, error) {
// no gatewayclient needed
}
// Keycloak client is optional, so if it stays nil, it's fine.
var keyCloakClient keycloak.Client
if options.Config.Keycloak.BasePath != "" {
kcc := options.Config.Keycloak
if kcc.ClientID == "" || kcc.ClientSecret == "" || kcc.ClientRealm == "" || kcc.UserRealm == "" {
return nil, errors.New("keycloak client id, secret, client realm and user realm must be set")
}
keyCloakClient = keycloak.New(kcc.BasePath, kcc.ClientID, kcc.ClientSecret, kcc.ClientRealm, kcc.InsecureSkipVerify)
}
hClient := ehsvc.NewEventHistoryService("com.owncloud.api.eventhistory", ogrpc.DefaultClient())
var handle svc.Service
handle, err = svc.NewService(
svc.Logger(options.Logger),
@@ -142,6 +157,7 @@ func Server(opts ...Option) (http.Service, error) {
svc.WithRequireAdminMiddleware(requireAdminMiddleware),
svc.WithGatewayClient(gatewayClient),
svc.WithSearchService(searchsvc.NewSearchProviderService("com.owncloud.api.search", grpc.DefaultClient())),
svc.KeycloakCient(keyCloakClient),
)
if err != nil {

View File

@@ -13,7 +13,9 @@ import (
"github.com/go-chi/chi/v5"
"github.com/jellydator/ttlcache/v3"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
@@ -68,6 +70,8 @@ type Graph struct {
groupsCache *ttlcache.Cache[string, libregraph.Group]
eventsPublisher events.Publisher
searchService searchsvc.SearchProviderService
keycloakClient keycloak.Client
historyClient ehsvc.EventHistoryService
}
// ServeHTTP implements the Service interface.

View File

@@ -5,8 +5,10 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/roles"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
@@ -30,6 +32,8 @@ type Options struct {
RoleManager *roles.Manager
EventsPublisher events.Publisher
SearchService searchsvc.SearchProviderService
KeycloakClient keycloak.Client
EventHistoryClient ehsvc.EventHistoryService
}
// newOptions initializes the available default options.
@@ -126,3 +130,17 @@ func EventsPublisher(val events.Publisher) Option {
o.EventsPublisher = val
}
}
// KeycloakCient provides a function to set the KeycloakCient option.
func KeycloakCient(val keycloak.Client) Option {
return func(o *Options) {
o.KeycloakClient = val
}
}
// EventHistoryClient provides a function to set the EventHistoryClient option.
func KeycloakCient(val keycloak.Client) Option {
return func(o *Options) {
o.KeycloakClient = val
}
}

View File

@@ -68,19 +68,28 @@ func (g Graph) ExportPersonalData(w http.ResponseWriter, r *http.Request) {
}
// go start gathering
go g.GatherPersonalData(u, ref, r.Header.Get(revactx.TokenHeader), marsh)
go g.GatherPersonalData(ctx, u, ref, r.Header.Get(revactx.TokenHeader), marsh)
w.WriteHeader(http.StatusCreated)
}
// GatherPersonalData will all gather all personal data of the user and save it to a file in the users personal space
func (g Graph) GatherPersonalData(usr *user.User, ref *provider.Reference, token string, marsh Marshaller) {
func (g Graph) GatherPersonalData(ctx context.Context, usr *user.User, ref *provider.Reference, token string, marsh Marshaller) {
// create data
data := make(map[string]interface{})
// reva user
data["user"] = usr
// Check if we have a keycloak client, and if so, get the keycloak export.
if g.keycloakClient != nil {
kcd, err := g.keycloakClient.GetPIIReport(ctx, g.config.Keycloak.ClientID, usr)
if err != nil {
g.logger.Error().Err(err).Str("userID").Msg("cannot get keycloak personal data")
}
data["keycloak"] = kcd
}
// marshal
by, err := marsh(data)
if err != nil {
@@ -198,7 +207,6 @@ func createFolders(ctx context.Context, ref *provider.Reference, gwc gateway.Gat
}
}
return nil
}
func getLocation(r *http.Request) string {

View File

@@ -143,6 +143,7 @@ func NewService(opts ...Option) (Graph, error) {
gatewayClient: options.GatewayClient,
searchService: options.SearchService,
identityEducationBackend: options.IdentityEducationBackend,
keycloakClient: options.KeycloakClient,
}
if err := setIdentityBackends(options, &svc); err != nil {

View File

@@ -26,10 +26,10 @@ type Config struct {
// Keycloak configuration
type Keycloak struct {
BasePath string `yaml:"base_path" env:"INVITATIONS_KEYCLOAK_BASE_PATH" desc:"The URL to access keycloak."`
ClientID string `yaml:"client_id" env:"INVITATIONS_KEYCLOAK_CLIENT_ID" desc:"The client id to authenticate with keycloak."`
ClientSecret string `yaml:"client_secret" env:"INVITATIONS_KEYCLOAK_CLIENT_SECRET" desc:"The client secret to use in authentication."`
ClientRealm string `yaml:"client_realm" env:"INVITATIONS_KEYCLOAK_CLIENT_REALM" desc:"The realm the client is defined in."`
UserRealm string `yaml:"user_realm" env:"INVITATIONS_KEYCLOAK_USER_REALM" desc:"The realm users are defined."`
InsecureSkipVerify bool `yaml:"insecure_skip_verify" env:"INVITATIONS_KEYCLOAK_INSECURE_SKIP_VERIFY" desc:"Disable TLS certificate validation for Keycloak connections. Do not set this in production environments."`
BasePath string `yaml:"base_path" env:"KEYCLOAK_BASE_PATH;INVITATIONS_KEYCLOAK_BASE_PATH" desc:"The URL to access keycloak."`
ClientID string `yaml:"client_id" env:"KEYCLOAK_CLIENT_ID;INVITATIONS_KEYCLOAK_CLIENT_ID" desc:"The client id to authenticate with keycloak."`
ClientSecret string `yaml:"client_secret" env:"KEYCLOAK_CLIENT_SECRET;INVITATIONS_KEYCLOAK_CLIENT_SECRET" desc:"The client secret to use in authentication."`
ClientRealm string `yaml:"client_realm" env:"KEYCLOAK_CLIENT_REALM;INVITATIONS_KEYCLOAK_CLIENT_REALM" desc:"The realm the client is defined in."`
UserRealm string `yaml:"user_realm" env:"KEYCLOAK_USER_REALM;INVITATIONS_KEYCLOAK_USER_REALM" desc:"The realm users are defined."`
InsecureSkipVerify bool `yaml:"insecure_skip_verify" env:"KEYCLOAK_INSECURE_SKIP_VERIFY;INVITATIONS_KEYCLOAK_INSECURE_SKIP_VERIFY" desc:"Disable TLS certificate validation for Keycloak connections. Do not set this in production environments."`
}