package auth
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
)
func TestConfidentialOIDCOpaqueTokenIdentity(t *testing.T) {
const owner = "did:plc:abcdefghijklmnopqrstuvwx"
for _, subject := range []string{owner, "did:plc:someoneelse"} {
t.Run(subject, func(t *testing.T) {
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.URL.Path {
case "/token":
id, secret, ok := r.BasicAuth()
require.True(t, ok)
require.Equal(t, "client", id)
require.Equal(t, "secret", secret)
require.Equal(t, "authorization_code", r.FormValue("grant_type"))
require.Equal(t, "code", r.FormValue("code"))
// An ID token must not override the authenticated userinfo identity.
w.Write([]byte(`{"access_token":"private-opaque-token","token_type":"Bearer","id_token":"untrusted-id-token"}`))
case "/userinfo":
require.Equal(t, "Bearer private-opaque-token", r.Header.Get("Authorization"))
w.Write([]byte(`{"sub":"` + subject + `"}`))
default:
http.NotFound(w, r)
}
}))
defer server.Close()
p := &oidcProvider{oauth2: oauth2.Config{ClientID: "client", ClientSecret: "secret", Endpoint: oauth2.Endpoint{TokenURL: server.URL + "/token", AuthStyle: oauth2.AuthStyleInHeader}}, userInfoURL: server.URL + "/userinfo", userIDField: "/sub", allowedUsers: []string{owner}}
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, server.Client())
c, engine := gin.CreateTestContext(httptest.NewRecorder())
engine.ContextWithFallback = true
c.Request = httptest.NewRequest("GET", "https://gateway/callback?state=random-state&code=code", nil).WithContext(ctx)
token, err := p.Exchange(c, "random-state")
require.NoError(t, err)
allowed, user, _, err := p.Authorization(ctx, token)
require.NoError(t, err)
require.Equal(t, subject, user)
require.Equal(t, subject == owner, allowed)
})
}
}