hydra/oauth2/introspector_test.go

162 lines
5.5 KiB
Go

// Copyright © 2022 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package oauth2_test
import (
"context"
"fmt"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
hydra "github.com/ory/hydra-client-go/v2"
"github.com/ory/hydra/v2/driver"
"github.com/ory/hydra/v2/driver/config"
"github.com/ory/hydra/v2/fosite"
"github.com/ory/hydra/v2/internal"
"github.com/ory/hydra/v2/internal/testhelpers"
"github.com/ory/hydra/v2/oauth2"
"github.com/ory/hydra/v2/x"
"github.com/ory/x/configx"
"github.com/ory/x/prometheusx"
)
func TestIntrospectorSDK(t *testing.T) {
t.Parallel()
reg := testhelpers.NewRegistryMemory(t, driver.WithConfigOptions(configx.WithValues(map[string]any{
config.KeyScopeStrategy: "wildcard",
config.KeyIssuerURL: "https://foobariss",
})))
testhelpers.MustEnsureRegistryKeys(t, reg, x.OpenIDConnectKeyName)
internal.AddFositeExamples(t, reg)
tokens := Tokens(reg.OAuth2ProviderConfig(), 4)
c, err := reg.ClientManager().GetConcreteClient(context.TODO(), "my-client")
require.NoError(t, err)
c.Scope = "fosite,openid,photos,offline,foo.*"
require.NoError(t, reg.ClientManager().UpdateClient(context.TODO(), c))
metrics := prometheusx.NewMetricsManagerWithPrefix("hydra", prometheusx.HTTPMetrics, config.Version, config.Commit, config.Date)
router := x.NewRouterAdmin(metrics)
handler := oauth2.NewHandler(reg)
handler.SetAdminRoutes(router)
server := httptest.NewServer(router)
defer server.Close()
now := time.Now().UTC().Round(time.Minute)
createAccessTokenSession(t, "alice", "my-client", tokens[0].sig, now.Add(time.Hour), reg.OAuth2Storage(), fosite.Arguments{"core", "foo.*"})
createAccessTokenSession(t, "siri", "my-client", tokens[1].sig, now.Add(-time.Hour), reg.OAuth2Storage(), fosite.Arguments{"core", "foo.*"})
createAccessTokenSession(t, "my-client", "my-client", tokens[2].sig, now.Add(time.Hour), reg.OAuth2Storage(), fosite.Arguments{"hydra.introspect"})
createAccessTokenSessionPairwise(t, "alice", "my-client", tokens[3].sig, now.Add(time.Hour), reg.OAuth2Storage(), fosite.Arguments{"core", "foo.*"}, "alice-obfuscated")
t.Run("TestIntrospect", func(t *testing.T) {
for k, c := range []struct {
token string
description string
expectInactive bool
scopes []string
assert func(*testing.T, *hydra.IntrospectedOAuth2Token)
prepare func(*testing.T) *hydra.APIClient
}{
{
description: "should fail because invalid token was supplied",
token: "invalid",
expectInactive: true,
},
{
description: "should fail because token is expired",
token: tokens[1].tok,
expectInactive: true,
},
// {
// description: "should fail because username / password are invalid",
// token: tokens[0][1],
// expectInactive: true,
// expectCode: http.StatusUnauthorized,
// prepare: func(*testing.T) *hydra.OAuth2API.{
// client := hydra.Ne.OAuth2API.ithBasePath(server.URL)
// client.config.Username = "foo"
// client.config.Password = "foo"
// return client
// },
// },
{
description: "should fail because scope `bar` was requested but only `foo` is granted",
token: tokens[0].tok,
expectInactive: true,
scopes: []string{"bar"},
},
{
description: "should pass",
token: tokens[0].tok,
expectInactive: false,
},
{
description: "should pass using bearer authorization",
token: tokens[0].tok,
expectInactive: false,
scopes: []string{"foo.bar"},
assert: func(t *testing.T, c *hydra.IntrospectedOAuth2Token) {
assert.Equal(t, "alice", *c.Sub)
assert.Equal(t, now.Add(time.Hour).Unix(), *c.Exp, "expires at")
assert.Equal(t, now.Unix(), *c.Iat, "issued at")
assert.Equal(t, "https://foobariss", *c.Iss, "issuer")
assert.Equal(t, map[string]interface{}{"foo": "bar"}, c.Ext)
},
},
{
description: "should pass using regular authorization",
token: tokens[0].tok,
expectInactive: false,
scopes: []string{"foo.bar"},
assert: func(t *testing.T, c *hydra.IntrospectedOAuth2Token) {
assert.Equal(t, "core foo.*", *c.Scope)
assert.Equal(t, "alice", *c.Sub)
assert.Equal(t, now.Add(time.Hour).Unix(), *c.Exp, "expires at")
assert.Equal(t, now.Unix(), *c.Iat, "issued at")
assert.Equal(t, "https://foobariss", *c.Iss, "issuer")
assert.Equal(t, map[string]interface{}{"foo": "bar"}, c.Ext)
},
},
{
description: "should pass and check for obfuscated subject",
token: tokens[3].tok,
expectInactive: false,
scopes: []string{"foo.bar"},
assert: func(t *testing.T, c *hydra.IntrospectedOAuth2Token) {
assert.Equal(t, "alice", *c.Sub)
assert.Equal(t, "alice-obfuscated", *c.ObfuscatedSubject)
},
},
} {
t.Run(fmt.Sprintf("case=%d/description=%s", k, c.description), func(t *testing.T) {
var client *hydra.APIClient
if c.prepare != nil {
client = c.prepare(t)
} else {
client = hydra.NewAPIClient(hydra.NewConfiguration())
client.GetConfig().Servers = hydra.ServerConfigurations{{URL: server.URL}}
}
ctx, _, err := client.OAuth2API.IntrospectOAuth2Token(context.Background()).
Token(c.token).Scope(strings.Join(c.scopes, " ")).Execute()
require.NoError(t, err)
assert.Equal(t, c.expectInactive, !ctx.Active)
if !c.expectInactive && c.assert != nil {
c.assert(t, ctx)
}
})
}
})
}