Don't use the same secret for signing sessions and reva tokens

This commit is contained in:
André Duffeck committed 2026-10-06 09:52:02 +02:00
1 parent 713b9c5095
commit adc8a51657
9 files changed
+72 -9

No files matched your search

+2 -2
View File
@@ -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{
+6 -1
View File
@@ -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
+3 -2
View File
@@ -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.
+1 -1
View File
@@ -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),
+2 -1
View File
@@ -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)
}
})
}
}
+1 -1
View File
@@ -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,
},