@@ -150,7 +150,7 @@ type Config struct {
150
150
Logging loggingConf `yaml:"logging"`
151
151
ServiceDocumentation string `yaml:"service_documentation"`
152
152
Features featuresConf `yaml:"features"`
153
- Providers []ProviderConf `yaml:"providers"`
153
+ Providers []* ProviderConf `yaml:"providers"`
154
154
ServiceOperator ServiceOperatorConf `yaml:"service_operator"`
155
155
Caching cacheConf `yaml:"cache"`
156
156
}
@@ -189,6 +189,9 @@ func (c *featuresConf) validate() error {
189
189
if err := c .Notifications .validate (); err != nil {
190
190
return err
191
191
}
192
+ if err := c .SSH .validate (); err != nil {
193
+ return err
194
+ }
192
195
return nil
193
196
}
194
197
@@ -230,6 +233,27 @@ type sshConf struct {
230
233
PrivateKeys []ssh.Signer `yaml:"-"`
231
234
}
232
235
236
+ func (c * sshConf ) validate () error {
237
+ if ! c .Enabled {
238
+ return nil
239
+ }
240
+ if len (c .KeyFiles ) == 0 {
241
+ return errors .New ("invalid config: ssh feature enabled, but no ssh private key set" )
242
+ }
243
+ for _ , pkf := range c .KeyFiles {
244
+ pemBytes , err := os .ReadFile (pkf )
245
+ if err != nil {
246
+ return errors .Wrap (err , "reading ssh private key" )
247
+ }
248
+ signer , err := ssh .ParsePrivateKey (pemBytes )
249
+ if err != nil {
250
+ return errors .Wrap (err , "parsing ssh private key" )
251
+ }
252
+ c .PrivateKeys = append (c .PrivateKeys , signer )
253
+ }
254
+ return nil
255
+ }
256
+
233
257
type serverProfilesConf struct {
234
258
Enabled bool `yaml:"enabled"`
235
259
Groups profileGroupsCredentials `yaml:"groups"`
@@ -422,14 +446,43 @@ type signingConf struct {
422
446
423
447
// ProviderConf holds information about a provider
424
448
type ProviderConf struct {
425
- Issuer string `yaml:"issuer"`
426
- ClientID string `yaml:"client_id"`
427
- ClientSecret string `yaml:"client_secret"`
428
- Scopes []string `yaml:"scopes"`
429
- MytokensMaxLifetime int64 `yaml:"mytokens_max_lifetime"`
430
- Endpoints * oauth2x.Endpoints `yaml:"-"`
431
- Name string `yaml:"name"`
432
- Audience * model.AudienceConf `yaml:"audience"`
449
+ Issuer string `yaml:"issuer"`
450
+ ClientID string `yaml:"client_id"`
451
+ ClientSecret string `yaml:"client_secret"`
452
+ Scopes []string `yaml:"scopes"`
453
+ MytokensMaxLifetime int64 `yaml:"mytokens_max_lifetime"`
454
+ EnforcedRestrictions EnforcedRestrictionsConf `yaml:"enforced_restrictions"`
455
+ Endpoints * oauth2x.Endpoints `yaml:"-"`
456
+ Name string `yaml:"name"`
457
+ Audience * model.AudienceConf `yaml:"audience"`
458
+ }
459
+
460
+ // EnforcedRestrictionsConf is a type for holding configuration for enforced restrictions
461
+ type EnforcedRestrictionsConf struct {
462
+ Enabled bool `yaml:"-"`
463
+ ClaimSources map [string ]string `yaml:"claim_sources"`
464
+ DefaultTemplate string `yaml:"default_template"`
465
+ ForbidOnDefault bool `yaml:"forbid_on_default"`
466
+ HelpHTMLText string `yaml:"help_html"`
467
+ HelpHTMLFile string `yaml:"help_html_file"`
468
+ Mapping map [string ]string `yaml:"mapping"`
469
+ }
470
+
471
+ func (c * EnforcedRestrictionsConf ) validate () error {
472
+ if len (c .ClaimSources ) >= 1 {
473
+ c .Enabled = true
474
+ }
475
+ if c .HelpHTMLFile != "" {
476
+ content , err := os .ReadFile (c .HelpHTMLFile )
477
+ if err != nil {
478
+ return errors .Wrapf (
479
+ err ,
480
+ "error reading enforced restrictions help html file '%s'" , c .HelpHTMLFile ,
481
+ )
482
+ }
483
+ c .HelpHTMLText = string (content )
484
+ }
485
+ return nil
433
486
}
434
487
435
488
// ServiceOperatorConf is type holding the configuration for the service operator of this mytoken instance
@@ -541,6 +594,28 @@ func validate() error {
541
594
if conf == nil {
542
595
return errors .New ("config not set" )
543
596
}
597
+ if err := validateIssuerURL (); err != nil {
598
+ return err
599
+ }
600
+ if err := configureServerTLS (); err != nil {
601
+ return err
602
+ }
603
+ if err := validateConfigSections (); err != nil {
604
+ return err
605
+ }
606
+ if err := validateProviders (); err != nil {
607
+ return err
608
+ }
609
+ if conf .Features .GuestMode .Enabled {
610
+ addGuestModeProvider ()
611
+ }
612
+ if err := validateSigningConfig (); err != nil {
613
+ return err
614
+ }
615
+ return validateWebInterface ()
616
+ }
617
+
618
+ func validateIssuerURL () error {
544
619
if conf .IssuerURL == "" {
545
620
return errors .New ("invalid config: issuer_url not set" )
546
621
}
@@ -553,94 +628,106 @@ func validate() error {
553
628
return errors .Wrap (err , "invalid config: issuer_url not valid" )
554
629
}
555
630
conf .Host = u .Hostname ()
631
+ return nil
632
+ }
633
+
634
+ func configureServerTLS () error {
556
635
if conf .Server .TLS .Enabled {
557
636
if conf .Server .TLS .Key != "" && conf .Server .TLS .Cert != "" {
558
637
conf .Server .Port = 443
559
638
} else {
560
639
conf .Server .TLS .Enabled = false
561
640
}
562
641
}
563
- if err = conf .Logging .validate (); err != nil {
564
- return err
565
- }
566
- if err = conf .ServiceOperator .validate (); err != nil {
642
+ return nil
643
+ }
644
+
645
+ func validateConfigSections () error {
646
+ if err := conf .Logging .validate (); err != nil {
567
647
return err
568
648
}
569
- if err = conf .Features .validate (); err != nil {
649
+
650
+ if err := conf .ServiceOperator .validate (); err != nil {
570
651
return err
571
652
}
572
- if len (conf .Providers ) <= 0 {
653
+
654
+ return conf .Features .validate ()
655
+ }
656
+
657
+ func validateProviders () error {
658
+ if len (conf .Providers ) == 0 {
573
659
return errors .New ("invalid config: providers must have at least one entry" )
574
660
}
575
661
for i , p := range conf .Providers {
576
- if p .Issuer == "" {
577
- return errors .Errorf ("invalid config: provider.issuer not set (Index %d)" , i )
578
- }
579
- oc , err := oauth2x .NewConfig (context .Get (), p .Issuer )
580
- if err != nil {
581
- return errors .Errorf ("error '%s' for provider.issuer '%s' (Index %d)" , err , p .Issuer , i )
582
- }
583
- // Endpoints only returns an error if it does discovery but this was already done in NewConfig, so we can ignore
584
- // the error value
585
- p .Endpoints , _ = oc .Endpoints ()
586
- if p .ClientID == "" {
587
- return errors .Errorf ("invalid config: provider.clientid not set (Index %d)" , i )
588
- }
589
- if p .ClientSecret == "" {
590
- return errors .Errorf ("invalid config: provider.clientsecret not set (Index %d)" , i )
591
- }
592
- if len (p .Scopes ) <= 0 {
593
- return errors .Errorf ("invalid config: provider.scopes not set (Index %d)" , i )
594
- }
595
- if p .Audience == nil {
596
- p .Audience = & model.AudienceConf {RFC8707 : true }
597
- }
598
- if p .Audience .RFC8707 {
599
- p .Audience .RequestParameter = model .AudienceParameterResource
600
- p .Audience .SpaceSeparateAuds = false
601
- } else if p .Audience .RequestParameter == "" {
602
- p .Audience .RequestParameter = model .AudienceParameterResource
662
+ if err := validateProvider (p , i ); err != nil {
663
+ return err
603
664
}
604
665
conf .Providers [i ] = p
605
666
}
606
- if conf .Features .GuestMode .Enabled {
607
- iss := utils2 .CombineURLPath (conf .IssuerURL , paths .GetCurrentAPIPaths ().GuestModeOP )
608
- p := ProviderConf {
609
- Issuer : iss ,
610
- Name : "Guest Mode" ,
611
- Scopes : []string {"openid" },
612
- Endpoints : & oauth2x.Endpoints {
613
- Authorization : utils2 .CombineURLPath (iss , "auth" ),
614
- Token : utils2 .CombineURLPath (iss , "token" ),
615
- },
616
- }
617
- conf .Providers = append (conf .Providers , p )
667
+ return nil
668
+ }
669
+
670
+ func validateProvider (p * ProviderConf , i int ) error {
671
+ if p .Issuer == "" {
672
+ return errors .Errorf ("invalid config: provider.issuer not set (Index %d)" , i )
618
673
}
619
- if conf .IssuerURL == "" {
620
- return errors .New ("invalid config: issuer_url not set" )
674
+ if err := p .EnforcedRestrictions .validate (); err != nil {
675
+ return err
676
+ }
677
+ oc , err := oauth2x .NewConfig (context .Get (), p .Issuer )
678
+ if err != nil {
679
+ return errors .Errorf ("error '%s' for provider.issuer '%s' (Index %d)" , err , p .Issuer , i )
621
680
}
681
+ p .Endpoints , err = oc .Endpoints ()
682
+ if err != nil {
683
+ return errors .Errorf ("error '%s' for provider.issuer '%s' (Index %d)" , err , p .Issuer , i )
684
+ }
685
+ if p .ClientID == "" {
686
+ return errors .Errorf ("invalid config: provider.clientid not set (Index %d)" , i )
687
+ }
688
+ if p .ClientSecret == "" {
689
+ return errors .Errorf ("invalid config: provider.clientsecret not set (Index %d)" , i )
690
+ }
691
+ if len (p .Scopes ) == 0 {
692
+ return errors .Errorf ("invalid config: provider.scopes not set (Index %d)" , i )
693
+ }
694
+ if p .Audience == nil {
695
+ p .Audience = & model.AudienceConf {RFC8707 : true }
696
+ }
697
+ if p .Audience .RFC8707 {
698
+ p .Audience .RequestParameter = model .AudienceParameterResource
699
+ p .Audience .SpaceSeparateAuds = false
700
+ } else if p .Audience .RequestParameter == "" {
701
+ p .Audience .RequestParameter = model .AudienceParameterResource
702
+ }
703
+ return nil
704
+ }
705
+
706
+ func addGuestModeProvider () {
707
+ iss := utils2 .CombineURLPath (conf .IssuerURL , paths .GetCurrentAPIPaths ().GuestModeOP )
708
+ p := & ProviderConf {
709
+ Issuer : iss ,
710
+ Name : "Guest Mode" ,
711
+ Scopes : []string {"openid" },
712
+ Endpoints : & oauth2x.Endpoints {
713
+ Authorization : utils2 .CombineURLPath (iss , "auth" ),
714
+ Token : utils2 .CombineURLPath (iss , "token" ),
715
+ },
716
+ }
717
+ conf .Providers = append (conf .Providers , p )
718
+ }
719
+
720
+ func validateSigningConfig () error {
622
721
if conf .Signing .Mytoken .KeyFile == "" {
623
722
return errors .New ("invalid config: signing keyfile not set" )
624
723
}
625
724
if conf .Signing .Mytoken .Alg == "" {
626
725
return errors .New ("invalid config: token signing alg not set" )
627
726
}
628
- if conf .Features .SSH .Enabled {
629
- if len (conf .Features .SSH .KeyFiles ) == 0 {
630
- return errors .New ("invalid config: ssh feature enabled, but no ssh private key set" )
631
- }
632
- for _ , pkf := range conf .Features .SSH .KeyFiles {
633
- pemBytes , err := os .ReadFile (pkf )
634
- if err != nil {
635
- return errors .Wrap (err , "reading ssh private key" )
636
- }
637
- signer , err := ssh .ParsePrivateKey (pemBytes )
638
- if err != nil {
639
- return errors .Wrap (err , "parsing ssh private key" )
640
- }
641
- conf .Features .SSH .PrivateKeys = append (conf .Features .SSH .PrivateKeys , signer )
642
- }
643
- }
727
+ return nil
728
+ }
729
+
730
+ func validateWebInterface () error {
644
731
if ! conf .Features .TokenInfo .Introspect .Enabled && conf .Features .WebInterface .Enabled {
645
732
return errors .New ("web interface requires tokeninfo.introspect to be enabled" )
646
733
}
0 commit comments