2020-12-09 01:33:08 +00:00
|
|
|
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2020-12-08 01:28:51 +00:00
|
|
|
package oidc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2020-12-08 18:17:03 +00:00
|
|
|
"github.com/ory/fosite/handler/oauth2"
|
|
|
|
|
|
|
|
"github.com/ory/fosite/handler/openid"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2020-12-08 01:28:51 +00:00
|
|
|
"github.com/ory/fosite"
|
|
|
|
"github.com/ory/fosite/compose"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TokenExchangeFactory(config *compose.Config, storage interface{}, strategy interface{}) interface{} {
|
2020-12-08 18:17:03 +00:00
|
|
|
return &TokenExchangeHandler{
|
|
|
|
strategy.(openid.OpenIDConnectTokenStrategy),
|
|
|
|
strategy.(oauth2.AccessTokenStrategy),
|
|
|
|
storage.(oauth2.AccessTokenStorage),
|
|
|
|
}
|
2020-12-08 01:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type TokenExchangeHandler struct {
|
2020-12-08 18:17:03 +00:00
|
|
|
idTokenStrategy openid.OpenIDConnectTokenStrategy
|
|
|
|
accessTokenStrategy oauth2.AccessTokenStrategy
|
|
|
|
accessTokenStorage oauth2.AccessTokenStorage
|
2020-12-08 01:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *TokenExchangeHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error {
|
2020-12-08 18:17:03 +00:00
|
|
|
if !(requester.GetGrantTypes().ExactOne("urn:ietf:params:oauth:grant-type:token-exchange")) {
|
|
|
|
return errors.WithStack(fosite.ErrUnknownRequest)
|
|
|
|
}
|
2020-12-08 01:28:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *TokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
|
2020-12-09 01:33:08 +00:00
|
|
|
if !(requester.GetGrantTypes().ExactOne("urn:ietf:params:oauth:grant-type:token-exchange")) {
|
|
|
|
return errors.WithStack(fosite.ErrUnknownRequest)
|
|
|
|
}
|
2020-12-08 18:17:03 +00:00
|
|
|
params := requester.GetRequestForm()
|
|
|
|
accessToken := params.Get("subject_token")
|
|
|
|
if err := t.accessTokenStrategy.ValidateAccessToken(ctx, requester, accessToken); err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
signature := t.accessTokenStrategy.AccessTokenSignature(accessToken)
|
|
|
|
accessTokenSession, err := t.accessTokenStorage.GetAccessTokenSession(ctx, signature, requester.GetSession())
|
|
|
|
if err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
if !accessTokenSession.GetGrantedScopes().Has("pinniped.sts.unrestricted") {
|
|
|
|
return errors.WithStack(fosite.ErrScopeNotGranted)
|
|
|
|
}
|
|
|
|
// TODO check the other requester fields
|
2020-12-09 01:33:08 +00:00
|
|
|
scopedDownRequester := fosite.NewAccessRequest(accessTokenSession.GetSession())
|
2020-12-08 18:17:03 +00:00
|
|
|
scopedDownRequester.GrantedAudience = []string{params.Get("audience")}
|
|
|
|
newToken, err := t.idTokenStrategy.GenerateIDToken(ctx, scopedDownRequester)
|
|
|
|
if err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
responder.SetAccessToken(newToken)
|
|
|
|
responder.SetTokenType("N_A")
|
|
|
|
responder.SetExtra("issued_token_type", "urn:ietf:params:oauth:token-type:jwt")
|
2020-12-08 01:28:51 +00:00
|
|
|
return nil
|
|
|
|
}
|