@@ -76,6 +76,7 @@ import (
76
76
"github.com/coder/coder/coderd/gitsshkey"
77
77
"github.com/coder/coder/coderd/httpapi"
78
78
"github.com/coder/coder/coderd/httpmw"
79
+ "github.com/coder/coder/coderd/oauthpki"
79
80
"github.com/coder/coder/coderd/prometheusmetrics"
80
81
"github.com/coder/coder/coderd/schedule"
81
82
"github.com/coder/coder/coderd/telemetry"
@@ -551,9 +552,9 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
551
552
}
552
553
}
553
554
554
- if cfg .OIDC .ClientSecret != "" {
555
+ if cfg .OIDC .ClientKeyFile != "" || cfg . OIDC . ClientSecret != "" {
555
556
if cfg .OIDC .ClientID == "" {
556
- return xerrors .Errorf ("OIDC client ID be set!" )
557
+ return xerrors .Errorf ("OIDC client ID must be set!" )
557
558
}
558
559
if cfg .OIDC .IssuerURL == "" {
559
560
return xerrors .Errorf ("OIDC issuer URL must be set!" )
@@ -578,15 +579,33 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
578
579
if slice .Contains (cfg .OIDC .Scopes , "groups" ) && cfg .OIDC .GroupField == "" {
579
580
cfg .OIDC .GroupField = "groups"
580
581
}
582
+ oauthCfg := & oauth2.Config {
583
+ ClientID : cfg .OIDC .ClientID .String (),
584
+ ClientSecret : cfg .OIDC .ClientSecret .String (),
585
+ RedirectURL : redirectURL .String (),
586
+ Endpoint : oidcProvider .Endpoint (),
587
+ Scopes : cfg .OIDC .Scopes ,
588
+ }
589
+
590
+ var useCfg httpmw.OAuth2Config = oauthCfg
591
+ if cfg .OIDC .ClientKeyFile != "" {
592
+ // PKI authentication is done in the params. If a
593
+ // counter example is found, we can add a config option to
594
+ // change this.
595
+ oauthCfg .Endpoint .AuthStyle = oauth2 .AuthStyleInParams
596
+ if cfg .OIDC .ClientSecret != "" {
597
+ return xerrors .Errorf ("cannot specify both oidc client secret and oidc client key file" )
598
+ }
599
+
600
+ pkiCfg , err := configureOIDCPKI (oauthCfg , cfg .OIDC .ClientKeyFile .Value (), cfg .OIDC .ClientCertFile .Value ())
601
+ if err != nil {
602
+ return xerrors .Errorf ("configure oauth pki authentication: %w" , err )
603
+ }
604
+ useCfg = pkiCfg
605
+ }
581
606
options .OIDCConfig = & coderd.OIDCConfig {
582
- OAuth2Config : & oauth2.Config {
583
- ClientID : cfg .OIDC .ClientID .String (),
584
- ClientSecret : cfg .OIDC .ClientSecret .String (),
585
- RedirectURL : redirectURL .String (),
586
- Endpoint : oidcProvider .Endpoint (),
587
- Scopes : cfg .OIDC .Scopes ,
588
- },
589
- Provider : oidcProvider ,
607
+ OAuth2Config : useCfg ,
608
+ Provider : oidcProvider ,
590
609
Verifier : oidcProvider .Verifier (& oidc.Config {
591
610
ClientID : cfg .OIDC .ClientID .String (),
592
611
}),
@@ -1494,6 +1513,33 @@ func configureTLS(tlsMinVersion, tlsClientAuth string, tlsCertFiles, tlsKeyFiles
1494
1513
return tlsConfig , nil
1495
1514
}
1496
1515
1516
+ func configureOIDCPKI (orig * oauth2.Config , keyFile string , certFile string ) (* oauthpki.Config , error ) {
1517
+ // Read the files
1518
+ keyData , err := os .ReadFile (keyFile )
1519
+ if err != nil {
1520
+ return nil , xerrors .Errorf ("read oidc client key file: %w" , err )
1521
+ }
1522
+
1523
+ var certData []byte
1524
+ // According to the spec, this is not required. So do not require it on the initial loading
1525
+ // of the PKI config.
1526
+ if certFile != "" {
1527
+ certData , err = os .ReadFile (certFile )
1528
+ if err != nil {
1529
+ return nil , xerrors .Errorf ("read oidc client cert file: %w" , err )
1530
+ }
1531
+ }
1532
+
1533
+ return oauthpki .NewOauth2PKIConfig (oauthpki.ConfigParams {
1534
+ ClientID : orig .ClientID ,
1535
+ TokenURL : orig .Endpoint .TokenURL ,
1536
+ Scopes : orig .Scopes ,
1537
+ PemEncodedKey : keyData ,
1538
+ PemEncodedCert : certData ,
1539
+ Config : orig ,
1540
+ })
1541
+ }
1542
+
1497
1543
func configureCAPool (tlsClientCAFile string , tlsConfig * tls.Config ) error {
1498
1544
if tlsClientCAFile != "" {
1499
1545
caPool := x509 .NewCertPool ()
0 commit comments