Merge branch 'main' into fosite-storage-gc
This commit is contained in:
commit
3c6d1a1924
@ -48,16 +48,16 @@ func oidcLoginCommand(loginFunc func(issuer string, clientID string, opts ...oid
|
|||||||
requestAudience string
|
requestAudience string
|
||||||
)
|
)
|
||||||
cmd.Flags().StringVar(&issuer, "issuer", "", "OpenID Connect issuer URL.")
|
cmd.Flags().StringVar(&issuer, "issuer", "", "OpenID Connect issuer URL.")
|
||||||
cmd.Flags().StringVar(&clientID, "client-id", "", "OpenID Connect client ID.")
|
cmd.Flags().StringVar(&clientID, "client-id", "pinniped-cli", "OpenID Connect client ID.")
|
||||||
cmd.Flags().Uint16Var(&listenPort, "listen-port", 0, "TCP port for localhost listener (authorization code flow only).")
|
cmd.Flags().Uint16Var(&listenPort, "listen-port", 0, "TCP port for localhost listener (authorization code flow only).")
|
||||||
cmd.Flags().StringSliceVar(&scopes, "scopes", []string{oidc.ScopeOfflineAccess, oidc.ScopeOpenID}, "OIDC scopes to request during login.")
|
cmd.Flags().StringSliceVar(&scopes, "scopes", []string{oidc.ScopeOfflineAccess, oidc.ScopeOpenID, "pinniped.sts.unrestricted"}, "OIDC scopes to request during login.")
|
||||||
cmd.Flags().BoolVar(&skipBrowser, "skip-browser", false, "Skip opening the browser (just print the URL).")
|
cmd.Flags().BoolVar(&skipBrowser, "skip-browser", false, "Skip opening the browser (just print the URL).")
|
||||||
cmd.Flags().StringVar(&sessionCachePath, "session-cache", filepath.Join(mustGetConfigDir(), "sessions.yaml"), "Path to session cache file.")
|
cmd.Flags().StringVar(&sessionCachePath, "session-cache", filepath.Join(mustGetConfigDir(), "sessions.yaml"), "Path to session cache file.")
|
||||||
cmd.Flags().StringSliceVar(&caBundlePaths, "ca-bundle", nil, "Path to TLS certificate authority bundle (PEM format, optional, can be repeated).")
|
cmd.Flags().StringSliceVar(&caBundlePaths, "ca-bundle", nil, "Path to TLS certificate authority bundle (PEM format, optional, can be repeated).")
|
||||||
cmd.Flags().BoolVar(&debugSessionCache, "debug-session-cache", false, "Print debug logs related to the session cache.")
|
cmd.Flags().BoolVar(&debugSessionCache, "debug-session-cache", false, "Print debug logs related to the session cache.")
|
||||||
cmd.Flags().StringVar(&requestAudience, "request-audience", "", "Request a token with an alternate audience using RF8693 token exchange.")
|
cmd.Flags().StringVar(&requestAudience, "request-audience", "", "Request a token with an alternate audience using RF8693 token exchange.")
|
||||||
mustMarkHidden(&cmd, "debug-session-cache")
|
mustMarkHidden(&cmd, "debug-session-cache")
|
||||||
mustMarkRequired(&cmd, "issuer", "client-id")
|
mustMarkRequired(&cmd, "issuer")
|
||||||
|
|
||||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||||
// Initialize the session cache.
|
// Initialize the session cache.
|
||||||
|
@ -42,12 +42,12 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
--ca-bundle strings Path to TLS certificate authority bundle (PEM format, optional, can be repeated).
|
--ca-bundle strings Path to TLS certificate authority bundle (PEM format, optional, can be repeated).
|
||||||
--client-id string OpenID Connect client ID.
|
--client-id string OpenID Connect client ID. (default "pinniped-cli")
|
||||||
-h, --help help for oidc
|
-h, --help help for oidc
|
||||||
--issuer string OpenID Connect issuer URL.
|
--issuer string OpenID Connect issuer URL.
|
||||||
--listen-port uint16 TCP port for localhost listener (authorization code flow only).
|
--listen-port uint16 TCP port for localhost listener (authorization code flow only).
|
||||||
--request-audience string Request a token with an alternate audience using RF8693 token exchange.
|
--request-audience string Request a token with an alternate audience using RF8693 token exchange.
|
||||||
--scopes strings OIDC scopes to request during login. (default [offline_access,openid])
|
--scopes strings OIDC scopes to request during login. (default [offline_access,openid,pinniped.sts.unrestricted])
|
||||||
--session-cache string Path to session cache file. (default "` + cfgDir + `/sessions.yaml")
|
--session-cache string Path to session cache file. (default "` + cfgDir + `/sessions.yaml")
|
||||||
--skip-browser Skip opening the browser (just print the URL).
|
--skip-browser Skip opening the browser (just print the URL).
|
||||||
`),
|
`),
|
||||||
@ -57,7 +57,7 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
args: []string{},
|
args: []string{},
|
||||||
wantError: true,
|
wantError: true,
|
||||||
wantStdout: here.Doc(`
|
wantStdout: here.Doc(`
|
||||||
Error: required flag(s) "client-id", "issuer" not set
|
Error: required flag(s) "issuer" not set
|
||||||
`),
|
`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mime"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -364,8 +365,12 @@ func (h *handlerState) tokenExchangeRFC8693(baseToken *oidctypes.Token) (*oidcty
|
|||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("unexpected HTTP response status %d", resp.StatusCode)
|
return nil, fmt.Errorf("unexpected HTTP response status %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
if contentType := resp.Header.Get("content-type"); contentType != "application/json" {
|
mediaType, _, err := mime.ParseMediaType(resp.Header.Get("content-type"))
|
||||||
return nil, fmt.Errorf("unexpected HTTP response content type %q", contentType)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode content-type header: %w", err)
|
||||||
|
}
|
||||||
|
if mediaType != "application/json" {
|
||||||
|
return nil, fmt.Errorf("unexpected HTTP response content type %q", mediaType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the JSON response body.
|
// Decode the JSON response body.
|
||||||
|
@ -164,11 +164,14 @@ func TestLogin(t *testing.T) {
|
|||||||
case "test-audience-produce-http-400":
|
case "test-audience-produce-http-400":
|
||||||
http.Error(w, "some server error", http.StatusBadRequest)
|
http.Error(w, "some server error", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
case "test-audience-produce-invalid-content-type":
|
||||||
|
w.Header().Set("content-type", "invalid/invalid;=")
|
||||||
|
return
|
||||||
case "test-audience-produce-wrong-content-type":
|
case "test-audience-produce-wrong-content-type":
|
||||||
w.Header().Set("content-type", "invalid")
|
w.Header().Set("content-type", "invalid")
|
||||||
return
|
return
|
||||||
case "test-audience-produce-invalid-json":
|
case "test-audience-produce-invalid-json":
|
||||||
w.Header().Set("content-type", "application/json")
|
w.Header().Set("content-type", "application/json;charset=UTF-8")
|
||||||
_, _ = w.Write([]byte(`{`))
|
_, _ = w.Write([]byte(`{`))
|
||||||
return
|
return
|
||||||
case "test-audience-produce-invalid-tokentype":
|
case "test-audience-produce-invalid-tokentype":
|
||||||
@ -601,6 +604,29 @@ func TestLogin(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: `failed to exchange token: unexpected HTTP response status 400`,
|
wantErr: `failed to exchange token: unexpected HTTP response status 400`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "with requested audience, session cache hit with valid token, but token exchange request returns invalid content-type header",
|
||||||
|
issuer: successServer.URL,
|
||||||
|
clientID: "test-client-id",
|
||||||
|
opt: func(t *testing.T) Option {
|
||||||
|
return func(h *handlerState) error {
|
||||||
|
cache := &mockSessionCache{t: t, getReturnsToken: &testToken}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
require.Equal(t, []SessionCacheKey{{
|
||||||
|
Issuer: successServer.URL,
|
||||||
|
ClientID: "test-client-id",
|
||||||
|
Scopes: []string{"test-scope"},
|
||||||
|
RedirectURI: "http://localhost:0/callback",
|
||||||
|
}}, cache.sawGetKeys)
|
||||||
|
require.Empty(t, cache.sawPutTokens)
|
||||||
|
})
|
||||||
|
require.NoError(t, WithSessionCache(cache)(h))
|
||||||
|
require.NoError(t, WithRequestAudience("test-audience-produce-invalid-content-type")(h))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wantErr: `failed to exchange token: failed to decode content-type header: mime: invalid media parameter`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "with requested audience, session cache hit with valid token, but token exchange request returns wrong content-type",
|
name: "with requested audience, session cache hit with valid token, but token exchange request returns wrong content-type",
|
||||||
issuer: successServer.URL,
|
issuer: successServer.URL,
|
||||||
|
Loading…
Reference in New Issue
Block a user