Skip to content

feat: add azure oidc PKI auth instead of client secret #9054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Aug 14, 2023
Merged
Prev Previous commit
Next Next commit
Refactor code into a method
  • Loading branch information
Emyrk committed Aug 11, 2023
commit ce39f2daca178ecff31641a13490ce96b7138c5c
4 changes: 4 additions & 0 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,10 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.

var useCfg httpmw.OAuth2Config = oauthCfg
if cfg.OIDC.ClientKeyFile != "" {
// PKI authentication is done in the params. If a
// counter example is found, we can add a config option to
// change this.
oauthCfg.Endpoint.AuthStyle = oauth2.AuthStyleInParams
if cfg.OIDC.ClientSecret != "" {
return xerrors.Errorf("cannot specify both oidc client secret and oidc client key file")
}
Expand Down
22 changes: 15 additions & 7 deletions coderd/oauthpki/oidcpki.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ func (ja *Config) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) strin

// Exchange includes the client_assertion signed JWT.
func (ja *Config) Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
signed, err := ja.jwtToken()
if err != nil {
return nil, xerrors.Errorf("failed jwt assertion: %w", err)
}
opts = append(opts,
oauth2.SetAuthURLParam("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
oauth2.SetAuthURLParam("client_assertion", signed),
)
return ja.cfg.Exchange(ctx, code, opts...)
}

func (ja *Config) jwtToken() (string, error) {
now := time.Now()
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": ja.clientID,
Expand All @@ -118,16 +130,12 @@ func (ja *Config) Exchange(ctx context.Context, code string, opts ...oauth2.Auth

signed, err := token.SignedString(ja.clientKey)
if err != nil {
return nil, xerrors.Errorf("failed to sign jwt assertion: %w", err)
return "", xerrors.Errorf("sign jwt assertion: %w", err)
}

opts = append(opts,
oauth2.SetAuthURLParam("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
oauth2.SetAuthURLParam("client_assertion", signed),
)
return ja.cfg.Exchange(ctx, code, opts...)
return signed, nil
}

func (ja *Config) TokenSource(ctx context.Context, token *oauth2.Token) oauth2.TokenSource {
// TODO: Hijack the http.Client to insert proper client auth assertions.
return ja.cfg.TokenSource(ctx, token)
}