Merge branch 'main' into fosite-storage-gc

This commit is contained in:
Ryan Richard 2020-12-10 10:45:26 -08:00
commit 3c6d1a1924
4 changed files with 40 additions and 9 deletions

View File

@ -48,16 +48,16 @@ func oidcLoginCommand(loginFunc func(issuer string, clientID string, opts ...oid
requestAudience string
)
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().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().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().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.")
mustMarkHidden(&cmd, "debug-session-cache")
mustMarkRequired(&cmd, "issuer", "client-id")
mustMarkRequired(&cmd, "issuer")
cmd.RunE = func(cmd *cobra.Command, args []string) error {
// Initialize the session cache.

View File

@ -42,12 +42,12 @@ func TestLoginOIDCCommand(t *testing.T) {
Flags:
--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
--issuer string OpenID Connect issuer URL.
--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.
--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")
--skip-browser Skip opening the browser (just print the URL).
`),
@ -57,7 +57,7 @@ func TestLoginOIDCCommand(t *testing.T) {
args: []string{},
wantError: true,
wantStdout: here.Doc(`
Error: required flag(s) "client-id", "issuer" not set
Error: required flag(s) "issuer" not set
`),
},
{

View File

@ -8,6 +8,7 @@ import (
"context"
"encoding/json"
"fmt"
"mime"
"net"
"net/http"
"net/url"
@ -364,8 +365,12 @@ func (h *handlerState) tokenExchangeRFC8693(baseToken *oidctypes.Token) (*oidcty
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected HTTP response status %d", resp.StatusCode)
}
if contentType := resp.Header.Get("content-type"); contentType != "application/json" {
return nil, fmt.Errorf("unexpected HTTP response content type %q", contentType)
mediaType, _, err := mime.ParseMediaType(resp.Header.Get("content-type"))
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.

View File

@ -164,11 +164,14 @@ func TestLogin(t *testing.T) {
case "test-audience-produce-http-400":
http.Error(w, "some server error", http.StatusBadRequest)
return
case "test-audience-produce-invalid-content-type":
w.Header().Set("content-type", "invalid/invalid;=")
return
case "test-audience-produce-wrong-content-type":
w.Header().Set("content-type", "invalid")
return
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(`{`))
return
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`,
},
{
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",
issuer: successServer.URL,