introspect
This commit is contained in:
parent
134999bc33
commit
138da8a208
13 changed files with 305 additions and 98 deletions
|
@ -4,10 +4,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/clientcredentials"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/utils"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
type ResourceServer interface {
|
||||
IntrospectionURL() string
|
||||
HttpClient() *http.Client
|
||||
AuthFn() interface{}
|
||||
}
|
||||
|
||||
type resourceServer struct {
|
||||
|
@ -23,6 +25,32 @@ type resourceServer struct {
|
|||
tokenURL string
|
||||
introspectURL string
|
||||
httpClient *http.Client
|
||||
authFn interface{}
|
||||
}
|
||||
|
||||
type jwtAccessTokenSource struct {
|
||||
clientID string
|
||||
audience []string
|
||||
PrivateKey []byte
|
||||
PrivateKeyID string
|
||||
}
|
||||
|
||||
func (j *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
|
||||
iat := time.Now()
|
||||
exp := iat.Add(time.Hour)
|
||||
assertion, err := GenerateJWTProfileToken(&oidc.JWTProfileAssertion{
|
||||
PrivateKeyID: j.PrivateKeyID,
|
||||
PrivateKey: j.PrivateKey,
|
||||
Issuer: j.clientID,
|
||||
Subject: j.clientID,
|
||||
Audience: j.audience,
|
||||
Expiration: oidc.Time(exp),
|
||||
IssuedAt: oidc.Time(iat),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oauth2.Token{AccessToken: assertion, TokenType: "Bearer", Expiry: exp}, nil
|
||||
}
|
||||
|
||||
func (r *resourceServer) IntrospectionURL() string {
|
||||
|
@ -33,8 +61,12 @@ func (r *resourceServer) HttpClient() *http.Client {
|
|||
return r.httpClient
|
||||
}
|
||||
|
||||
func (r *resourceServer) AuthFn() interface{} {
|
||||
return r.authFn
|
||||
}
|
||||
|
||||
func NewResourceServerClientCredentials(issuer, clientID, clientSecret string, option RSOption) (ResourceServer, error) {
|
||||
authorizer := func(tokenURL string) func(ctx context.Context) *http.Client {
|
||||
authorizer := func(tokenURL string) func(context.Context) *http.Client {
|
||||
return (&clientcredentials.Config{
|
||||
ClientID: clientID,
|
||||
ClientSecret: clientSecret,
|
||||
|
@ -44,20 +76,52 @@ func NewResourceServerClientCredentials(issuer, clientID, clientSecret string, o
|
|||
return newResourceServer(issuer, authorizer, option)
|
||||
}
|
||||
func NewResourceServerJWTProfile(issuer, clientID, keyID string, key []byte, options ...RSOption) (ResourceServer, error) {
|
||||
authorizer := func(tokenURL string) func(ctx context.Context) *http.Client {
|
||||
return (&jwt.Config{
|
||||
Email: clientID,
|
||||
Subject: clientID,
|
||||
PrivateKey: key,
|
||||
PrivateKeyID: keyID,
|
||||
Audience: issuer,
|
||||
TokenURL: tokenURL,
|
||||
}).Client
|
||||
ts := &jwtAccessTokenSource{
|
||||
clientID: clientID,
|
||||
PrivateKey: key,
|
||||
PrivateKeyID: keyID,
|
||||
audience: []string{issuer},
|
||||
}
|
||||
|
||||
//authorizer := func(tokenURL string) func(context.Context) *http.Client {
|
||||
// return func(ctx context.Context) *http.Client {
|
||||
// return oauth2.NewClient(ctx, oauth2.ReuseTokenSource(token, ts))
|
||||
// }
|
||||
//}
|
||||
authorizer := utils.FormAuthorization(func(values url.Values) {
|
||||
token, err := ts.Token()
|
||||
if err != nil {
|
||||
//return nil, err
|
||||
}
|
||||
values.Set("client_assertion", token.AccessToken)
|
||||
})
|
||||
return newResourceServer(issuer, authorizer, options...)
|
||||
}
|
||||
|
||||
func newResourceServer(issuer string, authorizer func(tokenURL string) func(ctx context.Context) *http.Client, options ...RSOption) (*resourceServer, error) {
|
||||
//
|
||||
//func newResourceServer(issuer string, authorizer func(tokenURL string) func(ctx context.Context) *http.Client, options ...RSOption) (*resourceServer, error) {
|
||||
// rp := &resourceServer{
|
||||
// issuer: issuer,
|
||||
// httpClient: utils.DefaultHTTPClient,
|
||||
// }
|
||||
// for _, optFunc := range options {
|
||||
// optFunc(rp)
|
||||
// }
|
||||
// if rp.introspectURL == "" || rp.tokenURL == "" {
|
||||
// endpoints, err := Discover(rp.issuer, rp.httpClient)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// rp.tokenURL = endpoints.TokenURL
|
||||
// rp.introspectURL = endpoints.IntrospectURL
|
||||
// }
|
||||
// if rp.introspectURL == "" || rp.tokenURL == "" {
|
||||
// return nil, errors.New("introspectURL and/or tokenURL is empty: please provide with either `WithStaticEndpoints` or a discovery url")
|
||||
// }
|
||||
// //rp.httpClient = authorizer(rp.tokenURL)(context.WithValue(context.Background(), oauth2.HTTPClient, rp.HttpClient()))
|
||||
// return rp, nil
|
||||
//}
|
||||
func newResourceServer(issuer string, authorizer interface{}, options ...RSOption) (*resourceServer, error) {
|
||||
rp := &resourceServer{
|
||||
issuer: issuer,
|
||||
httpClient: utils.DefaultHTTPClient,
|
||||
|
@ -76,7 +140,8 @@ func newResourceServer(issuer string, authorizer func(tokenURL string) func(ctx
|
|||
if rp.introspectURL == "" || rp.tokenURL == "" {
|
||||
return nil, errors.New("introspectURL and/or tokenURL is empty: please provide with either `WithStaticEndpoints` or a discovery url")
|
||||
}
|
||||
rp.httpClient = authorizer(rp.tokenURL)(context.WithValue(context.Background(), oauth2.HTTPClient, rp.HttpClient()))
|
||||
//rp.httpClient = authorizer(rp.tokenURL)(context.WithValue(context.Background(), oauth2.HTTPClient, rp.HttpClient()))
|
||||
rp.authFn = authorizer
|
||||
return rp, nil
|
||||
}
|
||||
|
||||
|
@ -85,6 +150,7 @@ func NewResourceServerFromKeyFile(path string, options ...RSOption) (ResourceSer
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Issuer = "http://localhost:50002/oauth/v2"
|
||||
return NewResourceServerJWTProfile(c.Issuer, c.ClientID, c.KeyID, []byte(c.Key), options...)
|
||||
}
|
||||
|
||||
|
@ -106,7 +172,7 @@ func WithStaticEndpoints(tokenURL, introspectURL string) RSOption {
|
|||
}
|
||||
|
||||
func Introspect(ctx context.Context, rp ResourceServer, token string) (oidc.IntrospectionResponse, error) {
|
||||
req, err := utils.FormRequest(rp.IntrospectionURL(), &oidc.IntrospectionRequest{Token: token}, encoder, nil)
|
||||
req, err := utils.FormRequest(rp.IntrospectionURL(), &oidc.IntrospectionRequest{Token: token}, encoder, rp.AuthFn())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue