mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-10-07 03:11:57 -04:00
Don't use the same secret for signing sessions and reva tokens
This commit is contained in:
1 parent
713b9c5095
commit
adc8a51657
9 files changed
+72
-9
No files matched your search
@@ -104,7 +104,7 @@ func CreateConfig(insecure, forceOverwrite, diff bool, configPath, adminPassword
|
||||
return fmt.Errorf("could not generate random secret for urlSigningSecret: %s", err)
|
||||
}
|
||||
}
|
||||
authGuestJWTSecret = oldCfg.AuthGuest.TokenManager.JWTSecret
|
||||
authGuestJWTSecret = oldCfg.AuthGuest.JWT.Secret
|
||||
if authGuestJWTSecret == "" {
|
||||
authGuestJWTSecret, err = generators.GenerateRandomPassword(passwordLength)
|
||||
if err != nil {
|
||||
@@ -226,7 +226,7 @@ func CreateConfig(insecure, forceOverwrite, diff bool, configPath, adminPassword
|
||||
},
|
||||
AuthGuest: AuthGuest{
|
||||
ServiceAccount: serviceAccount,
|
||||
TokenManager: TokenManager{JWTSecret: authGuestJWTSecret},
|
||||
JWT: AuthGuestJWT{Secret: authGuestJWTSecret},
|
||||
},
|
||||
Users: UsersAndGroupsService{
|
||||
Drivers: LdapBasedService{
|
||||
|
||||
@@ -57,7 +57,12 @@ type Activitylog struct {
|
||||
// AuthGuest is the configuration for the auth-guest service
|
||||
type AuthGuest struct {
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
TokenManager TokenManager `yaml:"token_manager"`
|
||||
JWT AuthGuestJWT `yaml:"jwt"`
|
||||
}
|
||||
|
||||
// AuthGuestJWT is the configuration for the guest session tokens
|
||||
type AuthGuestJWT struct {
|
||||
Secret string `yaml:"secret"`
|
||||
}
|
||||
|
||||
// App is the configuration for the collaboration service
|
||||
|
||||
@@ -41,7 +41,7 @@ sequenceDiagram
|
||||
Redeem->>+Reva: Get Share
|
||||
Reva->>-Redeem: Share
|
||||
Note right of Redeem: Validate Share, Mark Token used
|
||||
Redeem->>-Web: Set Cookie, return shareid
|
||||
Redeem->>-Web: Set Cookie, return shareid
|
||||
Note right of Web: HTTP only cookie with signed JWT (JWT lifetime 24h)
|
||||
Web->>+Proxy: "/graph/me/drives/sharedWithMe"
|
||||
Proxy->>+Reva: validate token extracted from JWT
|
||||
@@ -91,7 +91,8 @@ the event consumer, set `AUTH_GUEST_HTTP_DISABLED=true`.
|
||||
|
||||
Relevant options:
|
||||
|
||||
- `AUTH_GUEST_JWT_SECRET` — secret used to sign session tokens.
|
||||
- `AUTH_GUEST_SESSION_JWT_SECRET` — secret used to sign guest session tokens.
|
||||
It must differ from `OC_JWT_SECRET`.
|
||||
- `AUTH_GUEST_JWT_COOKIE_NAME`, `AUTH_GUEST_JWT_TTL` — session cookie name and
|
||||
lifetime.
|
||||
- `AUTH_GUEST_TOKENS_STORAGE_ROOT` — where guest link token records are stored.
|
||||
|
||||
@@ -79,7 +79,7 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
|
||||
tokenSvc := token.NewTokenService()
|
||||
store := storage.NewFileManager(cfg.Storage.RootDirectory)
|
||||
jwtService := jwt.NewJwtService(cfg.TokenManager.JWTSecret, cfg.JWT.TTL)
|
||||
jwtService := jwt.NewJwtService(cfg.JWT.Secret, cfg.JWT.TTL)
|
||||
|
||||
authGuest := authguest.NewAuthGuestService(tokenSvc, store,
|
||||
authguest.GatewaySelector(gatewaySelector),
|
||||
|
||||
@@ -89,11 +89,12 @@ type Storage struct {
|
||||
|
||||
// TokenManager is the config for using the reva token manager
|
||||
type TokenManager struct {
|
||||
JWTSecret string `yaml:"jwt_secret" env:"AUTH_GUEST_JWT_SECRET" desc:"The secret to mint and validate jwt tokens." introductionVersion:"%%NEXT%%"`
|
||||
JWTSecret string `yaml:"jwt_secret" env:"OC_JWT_SECRET;AUTH_GUEST_JWT_SECRET" desc:"The secret to mint and validate jwt tokens." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
|
||||
// JWT defines the configuration for guest session tokens.
|
||||
type JWT struct {
|
||||
Secret string `yaml:"secret" env:"AUTH_GUEST_SESSION_JWT_SECRET" desc:"The secret used to sign and validate guest session tokens. It must differ from OC_JWT_SECRET." introductionVersion:"%%NEXT%%" mask:"password"`
|
||||
CookieName string `yaml:"cookie_name" env:"AUTH_GUEST_JWT_COOKIE_NAME" desc:"The name of the session cookie set when a guest token is redeemed." introductionVersion:"%%NEXT%%"`
|
||||
TTL time.Duration `yaml:"ttl" env:"AUTH_GUEST_JWT_TTL" desc:"The lifetime of a redeemed guest session token." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
@@ -79,7 +79,11 @@ func EnsureDefaults(cfg *config.Config) {
|
||||
cfg.GRPC.TLS = structs.CopyOrZeroValue(cfg.Commons.GRPCServiceTLS)
|
||||
}
|
||||
|
||||
if cfg.TokenManager == nil {
|
||||
if cfg.TokenManager == nil && cfg.Commons != nil && cfg.Commons.TokenManager != nil {
|
||||
cfg.TokenManager = &config.TokenManager{
|
||||
JWTSecret: cfg.Commons.TokenManager.JWTSecret,
|
||||
}
|
||||
} else if cfg.TokenManager == nil {
|
||||
cfg.TokenManager = &config.TokenManager{}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
occfg "github.com/opencloud-eu/opencloud/pkg/config"
|
||||
ocdefaults "github.com/opencloud-eu/opencloud/pkg/config/defaults"
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-guest/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-guest/pkg/config/defaults"
|
||||
@@ -41,5 +43,17 @@ func Validate(cfg *config.Config) error {
|
||||
if cfg.TokenManager == nil || cfg.TokenManager.JWTSecret == "" {
|
||||
return shared.MissingJWTTokenError(cfg.Service.Name)
|
||||
}
|
||||
if cfg.JWT.Secret == "" {
|
||||
return fmt.Errorf("the guest session secret has not been set properly in your config for %s. "+
|
||||
"Make sure your %s config contains the proper values "+
|
||||
"(e.g. by using 'opencloud init --diff' and applying the patch or setting a value manually in "+
|
||||
"the config/corresponding environment variable AUTH_GUEST_SESSION_JWT_SECRET)",
|
||||
cfg.Service.Name, ocdefaults.BaseConfigPath())
|
||||
}
|
||||
// The guest session token and the reva access token are both HS256 JWTs. Signing them
|
||||
// with the same key would make them interchangeable.
|
||||
if cfg.JWT.Secret == cfg.TokenManager.JWTSecret {
|
||||
return fmt.Errorf("the guest session secret (AUTH_GUEST_SESSION_JWT_SECRET) of %s must differ from the jwt secret (OC_JWT_SECRET)", cfg.Service.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2026 OpenCloud GmbH <mail@opencloud.eu>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/auth-guest/pkg/config"
|
||||
)
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
jwtSecret string
|
||||
sessionSecret string
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "distinct secrets", jwtSecret: "reva-secret", sessionSecret: "session-secret"},
|
||||
{name: "missing jwt secret", sessionSecret: "session-secret", wantErr: true},
|
||||
{name: "missing session secret", jwtSecret: "reva-secret", wantErr: true},
|
||||
{name: "shared secret", jwtSecret: "same-secret", sessionSecret: "same-secret", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
TokenManager: &config.TokenManager{JWTSecret: tt.jwtSecret},
|
||||
JWT: config.JWT{Secret: tt.sessionSecret},
|
||||
}
|
||||
|
||||
err := Validate(cfg)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func GuestLinksConfigFromStruct(cfg *config.Config) map[string]any {
|
||||
"auth_managers": map[string]any{
|
||||
"guestlinks": map[string]any{
|
||||
"gateway_addr": cfg.RevaGateway,
|
||||
"jwt_secret": cfg.TokenManager.JWTSecret,
|
||||
"jwt_secret": cfg.JWT.Secret,
|
||||
"service_account_id": cfg.ServiceAccount.ServiceAccountID,
|
||||
"service_account_secret": cfg.ServiceAccount.ServiceAccountSecret,
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user