fix(oidc): add detailed trace/debug logs (#3012)

This adds significantly more detailed logging for most OpenID Connect handlers.
pull/3015/head
James Elliott 2022-03-16 09:55:38 +11:00 committed by GitHub
parent 2c3b507096
commit 9b779569f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 322 additions and 127 deletions

View File

@ -1,142 +1,145 @@
package handlers
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/jwt"
"github.com/authelia/authelia/v4/internal/logging"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/oidc"
"github.com/authelia/authelia/v4/internal/session"
)
func oidcAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, r *http.Request) {
ar, err := ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeRequest(ctx, r)
if err != nil {
logging.Logger().Errorf("Error occurred in NewAuthorizeRequest: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, ar, err)
var (
requester fosite.AuthorizeRequester
responder fosite.AuthorizeResponder
client *oidc.InternalClient
authTime time.Time
issuer string
err error
)
if requester, err = ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeRequest(ctx, r); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Authorization Request failed with error: %+v", rfc)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, err)
return
}
clientID := ar.GetClient().GetID()
client, err := ctx.Providers.OpenIDConnect.Store.GetInternalClient(clientID)
clientID := requester.GetClient().GetID()
if err != nil {
err := fmt.Errorf("unable to find related client configuration with name '%s': %v", ar.GetID(), err)
ctx.Logger.Error(err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, ar, err)
ctx.Logger.Debugf("Authorization Request with id '%s' on client with id '%s' is being processed", requester.GetID(), clientID)
if client, err = ctx.Providers.OpenIDConnect.Store.GetInternalClient(clientID); err != nil {
if errors.Is(err, fosite.ErrNotFound) {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: client was not found", requester.GetID(), clientID)
} else {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: failed to find client: %+v", requester.GetID(), clientID, err)
}
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, err)
return
}
if issuer, err = ctx.ExternalRootURL(); err != nil {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred determining issuer: %+v", requester.GetID(), clientID, err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not determine issuer."))
return
}
userSession := ctx.GetSession()
requestedScopes := ar.GetRequestedScopes()
requestedAudience := ar.GetRequestedAudience()
requestedScopes := requester.GetRequestedScopes()
requestedAudience := requester.GetRequestedAudience()
isAuthInsufficient := !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel)
if isAuthInsufficient || (isConsentMissing(userSession.OIDCWorkflowSession, requestedScopes, requestedAudience)) {
oidcAuthorizeHandleAuthorizationOrConsentInsufficient(ctx, userSession, client, isAuthInsufficient, rw, r, ar)
oidcAuthorizeHandleAuthorizationOrConsentInsufficient(ctx, userSession, client, isAuthInsufficient, rw, r, requester, issuer)
return
}
extraClaims := oidcGrantRequests(ar, requestedScopes, requestedAudience, &userSession)
extraClaims := oidcGrantRequests(requester, requestedScopes, requestedAudience, &userSession)
workflowCreated := time.Unix(userSession.OIDCWorkflowSession.CreatedTimestamp, 0)
userSession.OIDCWorkflowSession = nil
if err := ctx.SaveSession(userSession); err != nil {
ctx.Logger.Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
if err = ctx.SaveSession(userSession); err != nil {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred saving session: %+v", requester.GetID(), client.GetID(), err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not save the session."))
return
}
issuer, err := ctx.ExternalRootURL()
if err != nil {
ctx.Logger.Errorf("Error occurred obtaining issuer: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, ar, err)
if authTime, err = userSession.AuthenticatedTime(client.Policy); err != nil {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred checking authentication time: %+v", requester.GetID(), client.GetID(), err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not obtain the authentication time."))
return
}
authTime, err := userSession.AuthenticatedTime(client.Policy)
if err != nil {
ctx.Logger.Errorf("Error occurred obtaining authentication timestamp: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, ar, err)
ctx.Logger.Debugf("Authorization Request with id '%s' on client with id '%s' was successfully processed, proceeding to build Authorization Response", requester.GetID(), clientID)
subject := userSession.Username
oidcSession := oidc.NewSessionWithAuthorizeRequest(issuer, ctx.Providers.OpenIDConnect.KeyManager.GetActiveKeyID(),
subject, userSession.Username, extraClaims, authTime, workflowCreated, requester)
ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with claims: %+v",
requester.GetID(), oidcSession.ClientID, oidcSession.Subject, oidcSession.Username, oidcSession.Claims)
ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with headers: %+v",
requester.GetID(), oidcSession.ClientID, oidcSession.Subject, oidcSession.Username, oidcSession.Headers)
if responder, err = ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeResponse(ctx, requester, oidcSession); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Authorization Response for Request with id '%s' on client with id '%s' could not be created: %+v", requester.GetID(), clientID, rfc)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, err)
return
}
response, err := ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeResponse(ctx, ar, &oidc.OpenIDSession{
DefaultSession: &openid.DefaultSession{
Claims: &jwt.IDTokenClaims{
Subject: userSession.Username,
Issuer: issuer,
AuthTime: authTime,
RequestedAt: workflowCreated,
IssuedAt: time.Now(),
Nonce: ar.GetRequestForm().Get("nonce"),
Audience: ar.GetGrantedAudience(),
Extra: extraClaims,
},
Headers: &jwt.Headers{Extra: map[string]interface{}{
"kid": ctx.Providers.OpenIDConnect.KeyManager.GetActiveKeyID(),
}},
Subject: userSession.Username,
Username: userSession.Username,
},
ClientID: clientID,
})
if err != nil {
ctx.Logger.Errorf("Error occurred in NewAuthorizeResponse: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, ar, err)
return
}
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeResponse(rw, ar, response)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeResponse(rw, requester, responder)
}
func oidcAuthorizeHandleAuthorizationOrConsentInsufficient(
ctx *middlewares.AutheliaCtx, userSession session.UserSession, client *oidc.InternalClient, isAuthInsufficient bool,
rw http.ResponseWriter, r *http.Request,
ar fosite.AuthorizeRequester) {
issuer, err := ctx.ExternalRootURL()
if err != nil {
ctx.Logger.Error(err)
http.Error(rw, err.Error(), http.StatusBadRequest)
return
}
requester fosite.AuthorizeRequester, issuer string) {
redirectURL := fmt.Sprintf("%s%s", issuer, string(ctx.Request.RequestURI()))
ctx.Logger.Debugf("User %s must consent with scopes %s",
userSession.Username, strings.Join(ar.GetRequestedScopes(), ", "))
ctx.Logger.Debugf("Authorization Request with id '%s' on client with id '%s' requires user '%s' provides consent for scopes '%s'",
requester.GetID(), client.GetID(), userSession.Username, strings.Join(requester.GetRequestedScopes(), "', '"))
userSession.OIDCWorkflowSession = &session.OIDCWorkflowSession{
ClientID: client.ID,
RequestedScopes: ar.GetRequestedScopes(),
RequestedAudience: ar.GetRequestedAudience(),
ClientID: client.GetID(),
RequestedScopes: requester.GetRequestedScopes(),
RequestedAudience: requester.GetRequestedAudience(),
AuthURI: redirectURL,
TargetURI: ar.GetRedirectURI().String(),
TargetURI: requester.GetRedirectURI().String(),
RequiredAuthorizationLevel: client.Policy,
CreatedTimestamp: time.Now().Unix(),
}
if err := ctx.SaveSession(userSession); err != nil {
ctx.Logger.Errorf("Unable to save session: %v", err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred saving session for consent: %+v", requester.GetID(), client.GetID(), err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not save the session."))
return
}

View File

@ -3,20 +3,33 @@ package handlers
import (
"net/http"
"github.com/ory/fosite"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/oidc"
)
func oidcIntrospection(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *http.Request) {
oidcSession := newOpenIDSession("")
var (
responder fosite.IntrospectionResponder
err error
)
ir, err := ctx.Providers.OpenIDConnect.Fosite.NewIntrospectionRequest(ctx, req, oidcSession)
oidcSession := oidc.NewSession()
if responder, err = ctx.Providers.OpenIDConnect.Fosite.NewIntrospectionRequest(ctx, req, oidcSession); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Introspection Request failed with error: %+v", rfc)
if err != nil {
ctx.Logger.Errorf("Error occurred in NewIntrospectionRequest: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteIntrospectionError(rw, err)
return
}
ctx.Providers.OpenIDConnect.Fosite.WriteIntrospectionResponse(rw, ir)
requester := responder.GetAccessRequester()
ctx.Logger.Tracef("Introspection Request yeilded a %s (active: %t) requested at %s created with request id '%s' on client with id '%s'", responder.GetTokenUse(), responder.IsActive(), requester.GetRequestedAt().String(), requester.GetID(), requester.GetClient().GetID())
ctx.Providers.OpenIDConnect.Fosite.WriteIntrospectionResponse(rw, responder)
}

View File

@ -10,6 +10,6 @@ func oidcJWKs(ctx *middlewares.AutheliaCtx) {
ctx.SetContentType("application/json")
if err := json.NewEncoder(ctx).Encode(ctx.Providers.OpenIDConnect.KeyManager.GetKeySet()); err != nil {
ctx.Error(err, "failed to serve jwk set")
ctx.Error(err, "failed to serve json web key set")
}
}

View File

@ -3,11 +3,19 @@ package handlers
import (
"net/http"
"github.com/ory/fosite"
"github.com/authelia/authelia/v4/internal/middlewares"
)
func oidcRevocation(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *http.Request) {
err := ctx.Providers.OpenIDConnect.Fosite.NewRevocationRequest(ctx, req)
var err error
if err = ctx.Providers.OpenIDConnect.Fosite.NewRevocationRequest(ctx, req); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Revocation Request failed with error: %+v", rfc)
}
ctx.Providers.OpenIDConnect.Fosite.WriteRevocationResponse(rw, err)
}

View File

@ -6,35 +6,54 @@ import (
"github.com/ory/fosite"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/oidc"
)
func oidcToken(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *http.Request) {
oidcSession := newOpenIDSession("")
var (
requester fosite.AccessRequester
responder fosite.AccessResponder
err error
)
accessRequest, err := ctx.Providers.OpenIDConnect.Fosite.NewAccessRequest(ctx, req, oidcSession)
if err != nil {
ctx.Logger.Errorf("Error occurred in NewAccessRequest: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAccessError(rw, accessRequest, err)
oidcSession := oidc.NewSession()
if requester, err = ctx.Providers.OpenIDConnect.Fosite.NewAccessRequest(ctx, req, oidcSession); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Access Request failed with error: %+v", rfc)
ctx.Providers.OpenIDConnect.Fosite.WriteAccessError(rw, requester, err)
return
}
client := requester.GetClient()
ctx.Logger.Debugf("Access Request with id '%s' on client with id '%s' is being processed", requester.GetID(), client.GetID())
// If this is a client_credentials grant, grant all scopes the client is allowed to perform.
if accessRequest.GetGrantTypes().ExactOne("client_credentials") {
for _, scope := range accessRequest.GetRequestedScopes() {
if fosite.HierarchicScopeStrategy(accessRequest.GetClient().GetScopes(), scope) {
accessRequest.GrantScope(scope)
if requester.GetGrantTypes().ExactOne("client_credentials") {
for _, scope := range requester.GetRequestedScopes() {
if fosite.HierarchicScopeStrategy(client.GetScopes(), scope) {
requester.GrantScope(scope)
}
}
}
response, err := ctx.Providers.OpenIDConnect.Fosite.NewAccessResponse(ctx, accessRequest)
if err != nil {
ctx.Logger.Errorf("Error occurred in NewAccessResponse: %+v", err)
ctx.Providers.OpenIDConnect.Fosite.WriteAccessError(rw, accessRequest, err)
if responder, err = ctx.Providers.OpenIDConnect.Fosite.NewAccessResponse(ctx, requester); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("Access Response for Request with id '%s' failed to be created with error: %+v", requester.GetID(), rfc)
ctx.Providers.OpenIDConnect.Fosite.WriteAccessError(rw, requester, err)
return
}
ctx.Providers.OpenIDConnect.Fosite.WriteAccessResponse(rw, accessRequest, response)
ctx.Logger.Debugf("Access Request with id '%s' on client with id '%s' has successfully been processed", requester.GetID(), client.GetID())
ctx.Logger.Tracef("Access Request with id '%s' on client with id '%s' produced the following claims: %+v", requester.GetID(), client.GetID(), responder.ToMap())
ctx.Providers.OpenIDConnect.Fosite.WriteAccessResponse(rw, requester, responder)
}

View File

@ -15,13 +15,23 @@ import (
)
func oidcUserinfo(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *http.Request) {
session := newOpenIDSession("")
var (
tokenType fosite.TokenType
requester fosite.AccessRequester
client *oidc.InternalClient
err error
)
tokenType, ar, err := ctx.Providers.OpenIDConnect.Fosite.IntrospectToken(req.Context(), fosite.AccessTokenFromRequest(req), fosite.AccessToken, session)
if err != nil {
oidcSession := oidc.NewSession()
if tokenType, requester, err = ctx.Providers.OpenIDConnect.Fosite.IntrospectToken(
req.Context(), fosite.AccessTokenFromRequest(req), fosite.AccessToken, oidcSession); err != nil {
rfc := fosite.ErrorToRFC6749Error(err)
ctx.Logger.Errorf("UserInfo Request failed with error: %+v", rfc)
if rfc.StatusCode() == http.StatusUnauthorized {
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("error=%s,error_description=%s", rfc.ErrorField, rfc.GetDescription()))
rw.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer error="%s",error_description="%s"`, rfc.ErrorField, rfc.GetDescription()))
}
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
@ -29,22 +39,25 @@ func oidcUserinfo(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *htt
return
}
clientID := requester.GetClient().GetID()
if tokenType != fosite.AccessToken {
errStr := "authorization header must contain an OAuth access token."
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("error_description=\"%s\"", errStr))
ctx.Logger.Errorf("UserInfo Request with id '%s' on client with id '%s' failed with error: bearer authorization failed as the token is not an access_token", requester.GetID(), client.GetID())
errStr := "Only access tokens are allowed in the authorization header."
rw.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer error="invalid_token",error_description="%s"`, errStr))
ctx.Providers.OpenIDConnect.WriteErrorCode(rw, req, http.StatusUnauthorized, errors.New(errStr))
return
}
client, ok := ar.GetClient().(*oidc.InternalClient)
if !ok {
if client, err = ctx.Providers.OpenIDConnect.Store.GetInternalClient(clientID); err != nil {
ctx.Providers.OpenIDConnect.WriteError(rw, req, errors.WithStack(fosite.ErrServerError.WithHint("Unable to assert type of client")))
return
}
claims := ar.GetSession().(*oidc.OpenIDSession).IDTokenClaims().ToMap()
claims := requester.GetSession().(*oidc.OpenIDSession).IDTokenClaims().ToMap()
delete(claims, "jti")
delete(claims, "sid")
delete(claims, "at_hash")
@ -52,27 +65,49 @@ func oidcUserinfo(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *htt
delete(claims, "exp")
delete(claims, "nonce")
if audience, ok := claims["aud"].([]string); !ok || len(audience) == 0 {
claims["aud"] = []string{client.GetID()}
audience, ok := claims["aud"].([]string)
if !ok || len(audience) == 0 {
audience = []string{client.GetID()}
} else {
found := false
for _, aud := range audience {
if aud == clientID {
found = true
break
}
}
if found {
audience = append(audience, clientID)
}
}
claims["aud"] = audience
var (
keyID, token string
)
ctx.Logger.Tracef("UserInfo Response with id '%s' on client with id '%s' is being sent with the following claims: %+v", requester.GetID(), clientID, claims)
switch client.UserinfoSigningAlgorithm {
case "RS256":
claims["jti"] = uuid.New()
claims["iat"] = time.Now().Unix()
keyID, err := ctx.Providers.OpenIDConnect.KeyManager.Strategy().GetPublicKeyID(req.Context())
if err != nil {
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
if keyID, err = ctx.Providers.OpenIDConnect.KeyManager.Strategy().GetPublicKeyID(req.Context()); err != nil {
ctx.Providers.OpenIDConnect.WriteError(rw, req, fosite.ErrServerError.WithHintf("Could not find the active JWK."))
return
}
token, _, err := ctx.Providers.OpenIDConnect.KeyManager.Strategy().Generate(req.Context(), claims,
&jwt.Headers{
Extra: map[string]interface{}{"kid": keyID},
})
if err != nil {
headers := &jwt.Headers{
Extra: map[string]interface{}{"kid": keyID},
}
if token, _, err = ctx.Providers.OpenIDConnect.KeyManager.Strategy().Generate(req.Context(), claims, headers); err != nil {
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
return
@ -83,6 +118,6 @@ func oidcUserinfo(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *htt
case "none", "":
ctx.Providers.OpenIDConnect.Write(rw, req, claims)
default:
ctx.Providers.OpenIDConnect.WriteError(rw, req, errors.WithStack(fosite.ErrServerError.WithHintf("Unsupported userinfo signing algorithm '%s'.", client.UserinfoSigningAlgorithm)))
ctx.Providers.OpenIDConnect.WriteError(rw, req, errors.WithStack(fosite.ErrServerError.WithHintf("Unsupported UserInfo signing algorithm '%s'.", client.UserinfoSigningAlgorithm)))
}
}

View File

@ -2,8 +2,6 @@ package handlers
import (
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/jwt"
"github.com/authelia/authelia/v4/internal/oidc"
"github.com/authelia/authelia/v4/internal/session"
@ -21,17 +19,6 @@ func isConsentMissing(workflow *session.OIDCWorkflowSession, requestedScopes, re
len(requestedAudience) > 0 && utils.IsStringSlicesDifferentFold(requestedAudience, workflow.GrantedAudience)
}
func newOpenIDSession(subject string) *oidc.OpenIDSession {
return &oidc.OpenIDSession{
DefaultSession: &openid.DefaultSession{
Claims: new(jwt.IDTokenClaims),
Headers: new(jwt.Headers),
Subject: subject,
},
Extra: map[string]interface{}{},
}
}
func oidcGrantRequests(ar fosite.AuthorizeRequester, scopes, audiences []string, userSession *session.UserSession) (extraClaims map[string]interface{}) {
extraClaims = map[string]interface{}{}

View File

@ -2,16 +2,65 @@ package oidc
import (
"crypto/rsa"
"time"
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/storage"
"github.com/ory/fosite/token/jwt"
"github.com/ory/herodot"
"gopkg.in/square/go-jose.v2"
"github.com/authelia/authelia/v4/internal/authorization"
)
// NewSession creates a new OpenIDSession struct.
func NewSession() (session *OpenIDSession) {
return &OpenIDSession{
DefaultSession: &openid.DefaultSession{
Claims: &jwt.IDTokenClaims{
Extra: map[string]interface{}{},
},
Headers: &jwt.Headers{
Extra: map[string]interface{}{},
},
},
Extra: map[string]interface{}{},
}
}
// NewSessionWithAuthorizeRequest uses details from an AuthorizeRequester to generate an OpenIDSession.
func NewSessionWithAuthorizeRequest(issuer, kid, subject, username string, extra map[string]interface{},
authTime, requestedAt time.Time, requester fosite.AuthorizeRequester) (session *OpenIDSession) {
if extra == nil {
extra = make(map[string]interface{})
}
return &OpenIDSession{
DefaultSession: &openid.DefaultSession{
Claims: &jwt.IDTokenClaims{
Subject: subject,
Issuer: issuer,
AuthTime: authTime,
RequestedAt: requestedAt,
IssuedAt: time.Now(),
Nonce: requester.GetRequestForm().Get("nonce"),
Audience: requester.GetGrantedAudience(),
Extra: extra,
},
Headers: &jwt.Headers{
Extra: map[string]interface{}{
"kid": kid,
},
},
Subject: subject,
Username: username,
},
Extra: map[string]interface{}{},
ClientID: requester.GetClient().GetID(),
}
}
// OpenIDConnectProvider for OpenID Connect.
type OpenIDConnectProvider struct {
Fosite fosite.OAuth2Provider

View File

@ -0,0 +1,81 @@
package oidc
import (
"net/url"
"testing"
"time"
"github.com/google/uuid"
"github.com/ory/fosite"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewSession(t *testing.T) {
session := NewSession()
require.NotNil(t, session)
assert.Equal(t, "", session.ClientID)
assert.Equal(t, "", session.Username)
assert.Equal(t, "", session.Subject)
require.NotNil(t, session.Claims)
assert.NotNil(t, session.Claims.Extra)
assert.NotNil(t, session.Extra)
require.NotNil(t, session.Headers)
assert.NotNil(t, session.Headers.Extra)
}
func TestNewSessionWithAuthorizeRequest(t *testing.T) {
requestID := uuid.New()
subject := uuid.New()
formValues := url.Values{}
formValues.Set("nonce", "abc123xyzauthelia")
request := &fosite.AuthorizeRequest{
Request: fosite.Request{
ID: requestID.String(),
Form: formValues,
Client: &InternalClient{ID: "example"},
},
}
extra := map[string]interface{}{
"preferred_username": "john",
}
requested := time.Unix(1647332518, 0)
authAt := time.Unix(1647332500, 0)
issuer := "https://example.com"
session := NewSessionWithAuthorizeRequest(issuer, "primary", subject.String(), "john", extra, authAt, requested, request)
require.NotNil(t, session)
require.NotNil(t, session.Extra)
require.NotNil(t, session.Headers)
require.NotNil(t, session.Headers.Extra)
require.NotNil(t, session.Claims)
require.NotNil(t, session.Claims.Extra)
assert.Equal(t, "abc123xyzauthelia", session.Claims.Nonce)
assert.Equal(t, subject.String(), session.Claims.Subject)
assert.Equal(t, subject.String(), session.Subject)
assert.Equal(t, issuer, session.Claims.Issuer)
assert.Equal(t, "primary", session.Headers.Get("kid"))
assert.Equal(t, "example", session.ClientID)
assert.Equal(t, requested, session.Claims.RequestedAt)
assert.Equal(t, authAt, session.Claims.AuthTime)
assert.Greater(t, session.Claims.IssuedAt.Unix(), authAt.Unix())
assert.Equal(t, "john", session.Username)
require.Contains(t, session.Claims.Extra, "preferred_username")
assert.Equal(t, "john", session.Claims.Extra["preferred_username"])
session = NewSessionWithAuthorizeRequest(issuer, "primary", subject.String(), "john", nil, authAt, requested, request)
require.NotNil(t, session)
require.NotNil(t, session.Claims)
assert.NotNil(t, session.Claims.Extra)
}