feat(rp): extend tracing
This commit is contained in:
parent
e3e48882df
commit
d18aba8cb3
18 changed files with 198 additions and 7 deletions
|
@ -70,12 +70,16 @@ func authorizeCallbackHandler(authorizer Authorizer) func(http.ResponseWriter, *
|
|||
// Authorize handles the authorization request, including
|
||||
// parsing, validating, storing and finally redirecting to the login handler
|
||||
func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
||||
ctx, span := tracer.Start(r.Context(), "Authorize")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
authReq, err := ParseAuthorizeRequest(r, authorizer.Decoder())
|
||||
if err != nil {
|
||||
AuthRequestError(w, r, nil, err, authorizer)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
ctx = r.Context()
|
||||
if authReq.RequestParam != "" && authorizer.RequestObjectSupported() {
|
||||
err = ParseRequestObject(ctx, authReq, authorizer.Storage(), IssuerFromContext(ctx))
|
||||
if err != nil {
|
||||
|
@ -210,6 +214,9 @@ func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oi
|
|||
|
||||
// ValidateAuthRequest validates the authorize parameters and returns the userID of the id_token_hint if passed
|
||||
func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, verifier *IDTokenHintVerifier) (sub string, err error) {
|
||||
ctx, span := tracer.Start(ctx, "ValidateAuthRequest")
|
||||
defer span.End()
|
||||
|
||||
authReq.MaxAge, err = ValidateAuthReqPrompt(authReq.Prompt, authReq.MaxAge)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -310,7 +317,7 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
|
|||
return checkURIAgainstRedirects(client, uri)
|
||||
}
|
||||
if client.ApplicationType() == ApplicationTypeNative {
|
||||
return validateAuthReqRedirectURINative(client, uri, responseType)
|
||||
return validateAuthReqRedirectURINative(client, uri)
|
||||
}
|
||||
if err := checkURIAgainstRedirects(client, uri); err != nil {
|
||||
return err
|
||||
|
@ -330,7 +337,7 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
|
|||
}
|
||||
|
||||
// ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type
|
||||
func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error {
|
||||
func validateAuthReqRedirectURINative(client Client, uri string) error {
|
||||
parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
|
||||
isCustomSchema := !strings.HasPrefix(uri, "http://")
|
||||
if err := checkURIAgainstRedirects(client, uri); err == nil {
|
||||
|
@ -362,8 +369,8 @@ func equalURI(url1, url2 *url.URL) bool {
|
|||
return url1.Path == url2.Path && url1.RawQuery == url2.RawQuery
|
||||
}
|
||||
|
||||
func HTTPLoopbackOrLocalhost(rawurl string) (*url.URL, bool) {
|
||||
parsedURL, err := url.Parse(rawurl)
|
||||
func HTTPLoopbackOrLocalhost(rawURL string) (*url.URL, bool) {
|
||||
parsedURL, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
@ -409,6 +416,10 @@ func RedirectToLogin(authReqID string, client Client, w http.ResponseWriter, r *
|
|||
|
||||
// AuthorizeCallback handles the callback after authentication in the Login UI
|
||||
func AuthorizeCallback(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
||||
ctx, span := tracer.Start(r.Context(), "AuthorizeCallback")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
id, err := ParseAuthorizeCallbackRequest(r)
|
||||
if err != nil {
|
||||
AuthRequestError(w, r, nil, err, authorizer)
|
||||
|
@ -441,6 +452,10 @@ func ParseAuthorizeCallbackRequest(r *http.Request) (id string, err error) {
|
|||
|
||||
// AuthResponse creates the successful authentication response (either code or tokens)
|
||||
func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := tracer.Start(r.Context(), "ValidateAuthRequest")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
client, err := authorizer.Storage().GetClientByClientID(r.Context(), authReq.GetClientID())
|
||||
if err != nil {
|
||||
AuthRequestError(w, r, authReq, err, authorizer)
|
||||
|
@ -455,6 +470,10 @@ func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWri
|
|||
|
||||
// AuthResponseCode creates the successful code authentication response
|
||||
func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) {
|
||||
ctx, span := tracer.Start(r.Context(), "AuthResponseCode")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
code, err := CreateAuthRequestCode(r.Context(), authReq, authorizer.Storage(), authorizer.Crypto())
|
||||
if err != nil {
|
||||
AuthRequestError(w, r, authReq, err, authorizer)
|
||||
|
@ -519,6 +538,9 @@ func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthReque
|
|||
|
||||
// CreateAuthRequestCode creates and stores a code for the auth code response
|
||||
func CreateAuthRequestCode(ctx context.Context, authReq AuthRequest, storage Storage, crypto Crypto) (string, error) {
|
||||
ctx, span := tracer.Start(ctx, "CreateAuthRequestCode")
|
||||
defer span.End()
|
||||
|
||||
code, err := BuildAuthRequestCode(authReq, crypto)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -92,6 +92,9 @@ type ClientJWTProfile interface {
|
|||
}
|
||||
|
||||
func ClientJWTAuth(ctx context.Context, ca oidc.ClientAssertionParams, verifier ClientJWTProfile) (clientID string, err error) {
|
||||
ctx, span := tracer.Start(ctx, "ClientJWTAuth")
|
||||
defer span.End()
|
||||
|
||||
if ca.ClientAssertion == "" {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrNoClientCredentials)
|
||||
}
|
||||
|
@ -104,6 +107,10 @@ func ClientJWTAuth(ctx context.Context, ca oidc.ClientAssertionParams, verifier
|
|||
}
|
||||
|
||||
func ClientBasicAuth(r *http.Request, storage Storage) (clientID string, err error) {
|
||||
ctx, span := tracer.Start(r.Context(), "ClientBasicAuth")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
clientID, clientSecret, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrNoClientCredentials)
|
||||
|
@ -146,6 +153,10 @@ type clientData struct {
|
|||
// If no client id can be obtained by any method, oidc.ErrInvalidClient
|
||||
// is returned with ErrMissingClientID wrapped in it.
|
||||
func ClientIDFromRequest(r *http.Request, p ClientProvider) (clientID string, authenticated bool, err error) {
|
||||
ctx, span := tracer.Start(r.Context(), "ClientIDFromRequest")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
err = r.ParseForm()
|
||||
if err != nil {
|
||||
return "", false, oidc.ErrInvalidRequest().WithDescription("cannot parse form").WithParent(err)
|
||||
|
@ -171,7 +182,7 @@ func ClientIDFromRequest(r *http.Request, p ClientProvider) (clientID string, au
|
|||
}
|
||||
// if the client did not send a Basic Auth Header, ignore the `ErrNoClientCredentials`
|
||||
// but return other errors immediately
|
||||
if err != nil && !errors.Is(err, ErrNoClientCredentials) {
|
||||
if !errors.Is(err, ErrNoClientCredentials) {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,10 @@ func DeviceAuthorizationHandler(o OpenIDProvider) func(http.ResponseWriter, *htt
|
|||
}
|
||||
|
||||
func DeviceAuthorization(w http.ResponseWriter, r *http.Request, o OpenIDProvider) error {
|
||||
ctx, span := tracer.Start(r.Context(), "DeviceAuthorization")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
req, err := ParseDeviceCodeRequest(r, o)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -78,6 +82,9 @@ func DeviceAuthorization(w http.ResponseWriter, r *http.Request, o OpenIDProvide
|
|||
}
|
||||
|
||||
func createDeviceAuthorization(ctx context.Context, req *oidc.DeviceAuthorizationRequest, clientID string, o OpenIDProvider) (*oidc.DeviceAuthorizationResponse, error) {
|
||||
ctx, span := tracer.Start(ctx, "createDeviceAuthorization")
|
||||
defer span.End()
|
||||
|
||||
storage, err := assertDeviceStorage(o.Storage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -127,6 +134,10 @@ func createDeviceAuthorization(ctx context.Context, req *oidc.DeviceAuthorizatio
|
|||
}
|
||||
|
||||
func ParseDeviceCodeRequest(r *http.Request, o OpenIDProvider) (*oidc.DeviceAuthorizationRequest, error) {
|
||||
ctx, span := tracer.Start(r.Context(), "ParseDeviceCodeRequest")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
clientID, _, err := ClientIDFromRequest(r, o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -288,6 +299,9 @@ func (r *DeviceAuthorizationState) GetSubject() string {
|
|||
}
|
||||
|
||||
func CheckDeviceAuthorizationState(ctx context.Context, clientID, deviceCode string, exchanger Exchanger) (*DeviceAuthorizationState, error) {
|
||||
ctx, span := tracer.Start(ctx, "CheckDeviceAuthorization")
|
||||
defer span.End()
|
||||
|
||||
storage, err := assertDeviceStorage(exchanger.Storage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -135,6 +135,9 @@ func SubjectTypes(c Configuration) []string {
|
|||
}
|
||||
|
||||
func SigAlgorithms(ctx context.Context, storage DiscoverStorage) []string {
|
||||
ctx, span := tracer.Start(ctx, "SigAlgorithms")
|
||||
defer span.End()
|
||||
|
||||
algorithms, err := storage.SignatureAlgorithms(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
|
|
@ -20,6 +20,10 @@ func keysHandler(k KeyProvider) func(http.ResponseWriter, *http.Request) {
|
|||
}
|
||||
|
||||
func Keys(w http.ResponseWriter, r *http.Request, k KeyProvider) {
|
||||
ctx, span := tracer.Start(r.Context(), "Keys")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
keySet, err := k.KeySet(r.Context())
|
||||
if err != nil {
|
||||
httphelper.MarshalJSONWithStatus(w, err, http.StatusInternalServerError)
|
||||
|
|
|
@ -124,7 +124,13 @@ func (s *webServer) createRouter() {
|
|||
|
||||
func (s *webServer) endpointRoute(e *Endpoint, hf http.HandlerFunc) {
|
||||
if e != nil {
|
||||
s.router.HandleFunc(e.Relative(), hf)
|
||||
traceHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := tracer.Start(r.Context(), e.Relative())
|
||||
r = r.WithContext(ctx)
|
||||
hf(w, r)
|
||||
defer span.End()
|
||||
}
|
||||
s.router.HandleFunc(e.Relative(), traceHandler)
|
||||
s.logger.Info("registered route", "endpoint", e.Relative())
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +139,10 @@ type clientHandler func(w http.ResponseWriter, r *http.Request, client Client)
|
|||
|
||||
func (s *webServer) withClient(handler clientHandler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := tracer.Start(r.Context(), r.URL.Path)
|
||||
defer span.End()
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
client, err := s.verifyRequestClient(r)
|
||||
if err != nil {
|
||||
WriteError(w, r, err, s.getLogger(r.Context()))
|
||||
|
|
|
@ -79,6 +79,9 @@ func (s *LegacyServer) Endpoints() Endpoints {
|
|||
// AuthCallbackURL builds the url for the redirect (with the requestID) after a successful login
|
||||
func (s *LegacyServer) AuthCallbackURL() func(context.Context, string) string {
|
||||
return func(ctx context.Context, requestID string) string {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.AuthCallbackURL")
|
||||
defer span.End()
|
||||
|
||||
return s.endpoints.Authorization.Absolute(IssuerFromContext(ctx)) + authCallbackPathSuffix + "?id=" + requestID
|
||||
}
|
||||
}
|
||||
|
@ -98,12 +101,18 @@ func (s *LegacyServer) Ready(ctx context.Context, r *Request[struct{}]) (*Respon
|
|||
}
|
||||
|
||||
func (s *LegacyServer) Discovery(ctx context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.Discovery")
|
||||
defer span.End()
|
||||
|
||||
return NewResponse(
|
||||
createDiscoveryConfigV2(ctx, s.provider, s.provider.Storage(), &s.endpoints),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Keys(ctx context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.Keys")
|
||||
defer span.End()
|
||||
|
||||
keys, err := s.provider.Storage().KeySet(ctx)
|
||||
if err != nil {
|
||||
return nil, AsStatusError(err, http.StatusInternalServerError)
|
||||
|
@ -117,6 +126,9 @@ var (
|
|||
)
|
||||
|
||||
func (s *LegacyServer) VerifyAuthRequest(ctx context.Context, r *Request[oidc.AuthRequest]) (*ClientRequest[oidc.AuthRequest], error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.VerifyAuthRequest")
|
||||
defer span.End()
|
||||
|
||||
if r.Data.RequestParam != "" {
|
||||
if !s.provider.RequestObjectSupported() {
|
||||
return nil, oidc.ErrRequestNotSupported()
|
||||
|
@ -141,6 +153,9 @@ func (s *LegacyServer) VerifyAuthRequest(ctx context.Context, r *Request[oidc.Au
|
|||
}
|
||||
|
||||
func (s *LegacyServer) Authorize(ctx context.Context, r *ClientRequest[oidc.AuthRequest]) (_ *Redirect, err error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.Authorize")
|
||||
defer span.End()
|
||||
|
||||
userID, err := ValidateAuthReqIDTokenHint(ctx, r.Data.IDTokenHint, s.provider.IDTokenHintVerifier(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -153,6 +168,9 @@ func (s *LegacyServer) Authorize(ctx context.Context, r *ClientRequest[oidc.Auth
|
|||
}
|
||||
|
||||
func (s *LegacyServer) DeviceAuthorization(ctx context.Context, r *ClientRequest[oidc.DeviceAuthorizationRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.DeviceAuthorization")
|
||||
defer span.End()
|
||||
|
||||
response, err := createDeviceAuthorization(ctx, r.Data, r.Client.GetID(), s.provider)
|
||||
if err != nil {
|
||||
return nil, AsStatusError(err, http.StatusInternalServerError)
|
||||
|
@ -161,6 +179,9 @@ func (s *LegacyServer) DeviceAuthorization(ctx context.Context, r *ClientRequest
|
|||
}
|
||||
|
||||
func (s *LegacyServer) VerifyClient(ctx context.Context, r *Request[ClientCredentials]) (Client, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.VerifyClient")
|
||||
defer span.End()
|
||||
|
||||
if oidc.GrantType(r.Form.Get("grant_type")) == oidc.GrantTypeClientCredentials {
|
||||
storage, ok := s.provider.Storage().(ClientCredentialsStorage)
|
||||
if !ok {
|
||||
|
@ -201,6 +222,9 @@ func (s *LegacyServer) VerifyClient(ctx context.Context, r *Request[ClientCreden
|
|||
}
|
||||
|
||||
func (s *LegacyServer) CodeExchange(ctx context.Context, r *ClientRequest[oidc.AccessTokenRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.CodeExchange")
|
||||
defer span.End()
|
||||
|
||||
authReq, err := AuthRequestByCode(ctx, s.provider.Storage(), r.Data.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -221,6 +245,9 @@ func (s *LegacyServer) CodeExchange(ctx context.Context, r *ClientRequest[oidc.A
|
|||
}
|
||||
|
||||
func (s *LegacyServer) RefreshToken(ctx context.Context, r *ClientRequest[oidc.RefreshTokenRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.RefreshToken")
|
||||
defer span.End()
|
||||
|
||||
if !s.provider.GrantTypeRefreshTokenSupported() {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeRefreshToken)
|
||||
}
|
||||
|
@ -242,6 +269,9 @@ func (s *LegacyServer) RefreshToken(ctx context.Context, r *ClientRequest[oidc.R
|
|||
}
|
||||
|
||||
func (s *LegacyServer) JWTProfile(ctx context.Context, r *Request[oidc.JWTProfileGrantRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.JWTProfile")
|
||||
defer span.End()
|
||||
|
||||
exchanger, ok := s.provider.(JWTAuthorizationGrantExchanger)
|
||||
if !ok {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeBearer)
|
||||
|
@ -263,6 +293,9 @@ func (s *LegacyServer) JWTProfile(ctx context.Context, r *Request[oidc.JWTProfil
|
|||
}
|
||||
|
||||
func (s *LegacyServer) TokenExchange(ctx context.Context, r *ClientRequest[oidc.TokenExchangeRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.TokenExchange")
|
||||
defer span.End()
|
||||
|
||||
if !s.provider.GrantTypeTokenExchangeSupported() {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeTokenExchange)
|
||||
}
|
||||
|
@ -278,6 +311,9 @@ func (s *LegacyServer) TokenExchange(ctx context.Context, r *ClientRequest[oidc.
|
|||
}
|
||||
|
||||
func (s *LegacyServer) ClientCredentialsExchange(ctx context.Context, r *ClientRequest[oidc.ClientCredentialsRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.ClientCredentialsExchange")
|
||||
defer span.End()
|
||||
|
||||
storage, ok := s.provider.Storage().(ClientCredentialsStorage)
|
||||
if !ok {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeClientCredentials)
|
||||
|
@ -294,6 +330,9 @@ func (s *LegacyServer) ClientCredentialsExchange(ctx context.Context, r *ClientR
|
|||
}
|
||||
|
||||
func (s *LegacyServer) DeviceToken(ctx context.Context, r *ClientRequest[oidc.DeviceAccessTokenRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.DeviceToken")
|
||||
defer span.End()
|
||||
|
||||
if !s.provider.GrantTypeDeviceCodeSupported() {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeDeviceCode)
|
||||
}
|
||||
|
@ -314,6 +353,9 @@ func (s *LegacyServer) DeviceToken(ctx context.Context, r *ClientRequest[oidc.De
|
|||
}
|
||||
|
||||
func (s *LegacyServer) authenticateResourceClient(ctx context.Context, cc *ClientCredentials) (string, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.authenticateResourceClient")
|
||||
defer span.End()
|
||||
|
||||
if cc.ClientAssertion != "" {
|
||||
if jp, ok := s.provider.(ClientJWTProfile); ok {
|
||||
return ClientJWTAuth(ctx, oidc.ClientAssertionParams{ClientAssertion: cc.ClientAssertion}, jp)
|
||||
|
@ -327,6 +369,9 @@ func (s *LegacyServer) authenticateResourceClient(ctx context.Context, cc *Clien
|
|||
}
|
||||
|
||||
func (s *LegacyServer) Introspect(ctx context.Context, r *Request[IntrospectionRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.Introspect")
|
||||
defer span.End()
|
||||
|
||||
clientID, err := s.authenticateResourceClient(ctx, r.Data.ClientCredentials)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -345,6 +390,9 @@ func (s *LegacyServer) Introspect(ctx context.Context, r *Request[IntrospectionR
|
|||
}
|
||||
|
||||
func (s *LegacyServer) UserInfo(ctx context.Context, r *Request[oidc.UserInfoRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.UserInfo")
|
||||
defer span.End()
|
||||
|
||||
tokenID, subject, ok := getTokenIDAndSubject(ctx, s.provider, r.Data.AccessToken)
|
||||
if !ok {
|
||||
return nil, NewStatusError(oidc.ErrAccessDenied().WithDescription("access token invalid"), http.StatusUnauthorized)
|
||||
|
@ -358,6 +406,9 @@ func (s *LegacyServer) UserInfo(ctx context.Context, r *Request[oidc.UserInfoReq
|
|||
}
|
||||
|
||||
func (s *LegacyServer) Revocation(ctx context.Context, r *ClientRequest[oidc.RevocationRequest]) (*Response, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.Revocation")
|
||||
defer span.End()
|
||||
|
||||
var subject string
|
||||
doDecrypt := true
|
||||
if r.Data.TokenTypeHint != "access_token" {
|
||||
|
@ -387,6 +438,9 @@ func (s *LegacyServer) Revocation(ctx context.Context, r *ClientRequest[oidc.Rev
|
|||
}
|
||||
|
||||
func (s *LegacyServer) EndSession(ctx context.Context, r *Request[oidc.EndSessionRequest]) (*Redirect, error) {
|
||||
ctx, span := tracer.Start(ctx, "LegacyServer.EndSession")
|
||||
defer span.End()
|
||||
|
||||
session, err := ValidateEndSessionRequest(ctx, r.Data, s.provider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -27,6 +27,10 @@ func endSessionHandler(ender SessionEnder) func(http.ResponseWriter, *http.Reque
|
|||
}
|
||||
|
||||
func EndSession(w http.ResponseWriter, r *http.Request, ender SessionEnder) {
|
||||
ctx, span := tracer.Start(r.Context(), "EndSession")
|
||||
defer span.End()
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
req, err := ParseEndSessionRequest(r, ender.Decoder())
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -64,6 +68,9 @@ func ParseEndSessionRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.
|
|||
}
|
||||
|
||||
func ValidateEndSessionRequest(ctx context.Context, req *oidc.EndSessionRequest, ender SessionEnder) (*EndSessionRequest, error) {
|
||||
ctx, span := tracer.Start(ctx, "ValidateEndSessionRequest")
|
||||
defer span.End()
|
||||
|
||||
session := &EndSessionRequest{
|
||||
RedirectURI: ender.DefaultLogoutRedirectURI(),
|
||||
}
|
||||
|
|
|
@ -69,6 +69,9 @@ func CreateTokenResponse(ctx context.Context, request IDTokenRequest, client Cli
|
|||
}
|
||||
|
||||
func createTokens(ctx context.Context, tokenRequest TokenRequest, storage Storage, refreshToken string, client AccessTokenClient) (id, newRefreshToken string, exp time.Time, err error) {
|
||||
ctx, span := tracer.Start(ctx, "createTokens")
|
||||
defer span.End()
|
||||
|
||||
if needsRefreshToken(tokenRequest, client) {
|
||||
return storage.CreateAccessAndRefreshTokens(ctx, tokenRequest, refreshToken)
|
||||
}
|
||||
|
|
|
@ -193,6 +193,9 @@ func ValidateTokenExchangeRequest(
|
|||
clientID, clientSecret string,
|
||||
exchanger Exchanger,
|
||||
) (TokenExchangeRequest, Client, error) {
|
||||
ctx, span := tracer.Start(ctx, "ValidateTokenExchangeRequest")
|
||||
defer span.End()
|
||||
|
||||
if oidcTokenExchangeRequest.SubjectToken == "" {
|
||||
return nil, nil, oidc.ErrInvalidRequest().WithDescription("subject_token missing")
|
||||
}
|
||||
|
@ -231,6 +234,9 @@ func CreateTokenExchangeRequest(
|
|||
client Client,
|
||||
exchanger Exchanger,
|
||||
) (TokenExchangeRequest, error) {
|
||||
ctx, span := tracer.Start(ctx, "CreateTokenExchangeRequest")
|
||||
defer span.End()
|
||||
|
||||
teStorage, ok := exchanger.Storage().(TokenExchangeStorage)
|
||||
if !ok {
|
||||
return nil, unimplementedGrantError(oidc.GrantTypeTokenExchange)
|
||||
|
@ -294,6 +300,9 @@ func GetTokenIDAndSubjectFromToken(
|
|||
tokenType oidc.TokenType,
|
||||
isActor bool,
|
||||
) (tokenIDOrToken, subject string, claims map[string]any, ok bool) {
|
||||
ctx, span := tracer.Start(ctx, "GetTokenIDAndSubjectFromToken")
|
||||
defer span.End()
|
||||
|
||||
switch tokenType {
|
||||
case oidc.AccessTokenType:
|
||||
var accessTokenClaims *oidc.AccessTokenClaims
|
||||
|
@ -341,6 +350,9 @@ func GetTokenIDAndSubjectFromToken(
|
|||
|
||||
// AuthorizeTokenExchangeClient authorizes a client by validating the client_id and client_secret
|
||||
func AuthorizeTokenExchangeClient(ctx context.Context, clientID, clientSecret string, exchanger Exchanger) (client Client, err error) {
|
||||
ctx, span := tracer.Start(ctx, "AuthorizeTokenExchangeClient")
|
||||
defer span.End()
|
||||
|
||||
if err := AuthorizeClientIDSecret(ctx, clientID, clientSecret, exchanger.Storage()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -359,6 +371,8 @@ func CreateTokenExchangeResponse(
|
|||
client Client,
|
||||
creator TokenCreator,
|
||||
) (_ *oidc.TokenExchangeResponse, err error) {
|
||||
ctx, span := tracer.Start(ctx, "CreateTokenExchangeResponse")
|
||||
defer span.End()
|
||||
|
||||
var (
|
||||
token, refreshToken, tokenType string
|
||||
|
|
|
@ -28,6 +28,10 @@ func introspectionHandler(introspector Introspector) func(http.ResponseWriter, *
|
|||
}
|
||||
|
||||
func Introspect(w http.ResponseWriter, r *http.Request, introspector Introspector) {
|
||||
ctx, span := tracer.Start(r.Context(), "Introspect")
|
||||
defer span.End()
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
response := new(oidc.IntrospectionResponse)
|
||||
token, clientID, err := ParseTokenIntrospectionRequest(r, introspector)
|
||||
if err != nil {
|
||||
|
|
|
@ -141,6 +141,9 @@ func AuthorizeRefreshClient(ctx context.Context, tokenReq *oidc.RefreshTokenRequ
|
|||
// RefreshTokenRequestByRefreshToken returns the RefreshTokenRequest (data representing the original auth request)
|
||||
// corresponding to the refresh_token from Storage or an error
|
||||
func RefreshTokenRequestByRefreshToken(ctx context.Context, storage Storage, refreshToken string) (RefreshTokenRequest, error) {
|
||||
ctx, span := tracer.Start(ctx, "RefreshTokenRequestByRefreshToken")
|
||||
defer span.End()
|
||||
|
||||
request, err := storage.TokenRequestByRefreshToken(ctx, refreshToken)
|
||||
if err != nil {
|
||||
return nil, oidc.ErrInvalidGrant().WithParent(err)
|
||||
|
|
|
@ -37,6 +37,10 @@ func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Reque
|
|||
|
||||
// Exchange performs a token exchange appropriate for the grant type
|
||||
func Exchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||
ctx, span := tracer.Start(r.Context(), "Exchange")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
grantType := r.FormValue("grant_type")
|
||||
switch grantType {
|
||||
case string(oidc.GrantTypeCode):
|
||||
|
@ -115,6 +119,9 @@ func ParseAuthenticatedTokenRequest(r *http.Request, decoder httphelper.Decoder,
|
|||
|
||||
// AuthorizeClientIDSecret authorizes a client by validating the client_id and client_secret (Basic Auth and POST)
|
||||
func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string, storage Storage) error {
|
||||
ctx, span := tracer.Start(ctx, "AuthorizeClientIDSecret")
|
||||
defer span.End()
|
||||
|
||||
err := storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret)
|
||||
if err != nil {
|
||||
return oidc.ErrInvalidClient().WithDescription("invalid client_id / client_secret").WithParent(err)
|
||||
|
|
|
@ -32,6 +32,10 @@ func revocationHandler(revoker Revoker) func(http.ResponseWriter, *http.Request)
|
|||
}
|
||||
|
||||
func Revoke(w http.ResponseWriter, r *http.Request, revoker Revoker) {
|
||||
ctx, span := tracer.Start(r.Context(), "Revoke")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
token, tokenTypeHint, clientID, err := ParseTokenRevocationRequest(r, revoker)
|
||||
if err != nil {
|
||||
RevocationRequestError(w, r, err)
|
||||
|
@ -68,6 +72,10 @@ func Revoke(w http.ResponseWriter, r *http.Request, revoker Revoker) {
|
|||
}
|
||||
|
||||
func ParseTokenRevocationRequest(r *http.Request, revoker Revoker) (token, tokenTypeHint, clientID string, err error) {
|
||||
ctx, span := tracer.Start(r.Context(), "ParseTokenRevocationRequest")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
err = r.ParseForm()
|
||||
if err != nil {
|
||||
return "", "", "", oidc.ErrInvalidRequest().WithDescription("unable to parse request").WithParent(err)
|
||||
|
@ -148,6 +156,9 @@ func RevocationError(err error) StatusError {
|
|||
}
|
||||
|
||||
func getTokenIDAndSubjectForRevocation(ctx context.Context, userinfoProvider UserinfoProvider, accessToken string) (string, string, bool) {
|
||||
ctx, span := tracer.Start(ctx, "getTokenIDAndSubjectFromRevocation")
|
||||
defer span.End()
|
||||
|
||||
tokenIDSubject, err := userinfoProvider.Crypto().Decrypt(accessToken)
|
||||
if err == nil {
|
||||
splitToken := strings.Split(tokenIDSubject, ":")
|
||||
|
|
|
@ -24,6 +24,10 @@ func userinfoHandler(userinfoProvider UserinfoProvider) func(http.ResponseWriter
|
|||
}
|
||||
|
||||
func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoProvider) {
|
||||
ctx, span := tracer.Start(r.Context(), "Userinfo")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
accessToken, err := ParseUserinfoRequest(r, userinfoProvider.Decoder())
|
||||
if err != nil {
|
||||
http.Error(w, "access token missing", http.StatusUnauthorized)
|
||||
|
@ -44,6 +48,10 @@ func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoP
|
|||
}
|
||||
|
||||
func ParseUserinfoRequest(r *http.Request, decoder httphelper.Decoder) (string, error) {
|
||||
ctx, span := tracer.Start(r.Context(), "ParseUserinfoRequest")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
accessToken, err := getAccessToken(r)
|
||||
if err == nil {
|
||||
return accessToken, nil
|
||||
|
@ -61,6 +69,10 @@ func ParseUserinfoRequest(r *http.Request, decoder httphelper.Decoder) (string,
|
|||
}
|
||||
|
||||
func getAccessToken(r *http.Request) (string, error) {
|
||||
ctx, span := tracer.Start(r.Context(), "RefreshTokens")
|
||||
r = r.WithContext(ctx)
|
||||
defer span.End()
|
||||
|
||||
authHeader := r.Header.Get("authorization")
|
||||
if authHeader == "" {
|
||||
return "", errors.New("no auth header")
|
||||
|
@ -73,6 +85,9 @@ func getAccessToken(r *http.Request) (string, error) {
|
|||
}
|
||||
|
||||
func getTokenIDAndSubject(ctx context.Context, userinfoProvider UserinfoProvider, accessToken string) (string, string, bool) {
|
||||
ctx, span := tracer.Start(ctx, "getTokenIDAndSubject")
|
||||
defer span.End()
|
||||
|
||||
tokenIDSubject, err := userinfoProvider.Crypto().Decrypt(accessToken)
|
||||
if err == nil {
|
||||
splitToken := strings.Split(tokenIDSubject, ":")
|
||||
|
|
|
@ -30,6 +30,9 @@ func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTok
|
|||
|
||||
// VerifyAccessToken validates the access token (issuer, signature and expiration).
|
||||
func VerifyAccessToken[C oidc.Claims](ctx context.Context, token string, v *AccessTokenVerifier) (claims C, err error) {
|
||||
ctx, span := tracer.Start(ctx, "VerifyAccessToken")
|
||||
defer span.End()
|
||||
|
||||
var nilClaims C
|
||||
|
||||
decrypted, err := oidc.DecryptToken(token)
|
||||
|
|
|
@ -46,6 +46,9 @@ func (e IDTokenHintExpiredError) Is(err error) bool {
|
|||
// is returned of type [IDTokenHintExpiredError]. In that case the caller can choose to still
|
||||
// trust the token for cases like logout, as signature and other verifications succeeded.
|
||||
func VerifyIDTokenHint[C oidc.Claims](ctx context.Context, token string, v *IDTokenHintVerifier) (claims C, err error) {
|
||||
ctx, span := tracer.Start(ctx, "VerifyIDTokenHint")
|
||||
defer span.End()
|
||||
|
||||
var nilClaims C
|
||||
|
||||
decrypted, err := oidc.DecryptToken(token)
|
||||
|
|
|
@ -118,6 +118,9 @@ type jwtProfileKeySet struct {
|
|||
|
||||
// VerifySignature implements oidc.KeySet by getting the public key from Storage implementation
|
||||
func (k *jwtProfileKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error) {
|
||||
ctx, span := tracer.Start(ctx, "VerifySignature")
|
||||
defer span.End()
|
||||
|
||||
keyID, _ := oidc.GetKeyIDAndAlg(jws)
|
||||
key, err := k.storage.GetKeyByIDAndClientID(ctx, keyID, k.clientID)
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue