token, errors and more
This commit is contained in:
parent
89bcd1a0c3
commit
f04e7cf5b9
9 changed files with 64 additions and 24 deletions
|
@ -2,6 +2,7 @@ package mock
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
|
@ -32,6 +33,10 @@ func (a *AuthRequest) GetAudience() []string {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAuthTime() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetClientID() string {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWri
|
|||
|
||||
}
|
||||
}
|
||||
idToken, err := CreateIDToken("", authReq, accessToken, time.Now(), time.Now(), "", authorizer.Signer())
|
||||
idToken, err := CreateIDToken("", authReq, time.Duration(0), accessToken, authorizer.Signer())
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package op
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/schema"
|
||||
|
||||
|
@ -22,6 +23,7 @@ var (
|
|||
IntrospectionEndpoint: defaultIntrospectEndpoint,
|
||||
Userinfo: defaultUserinfoEndpoint,
|
||||
}
|
||||
DefaultIDTokenValidity = time.Duration(5 * time.Minute)
|
||||
)
|
||||
|
||||
type DefaultOP struct {
|
||||
|
@ -37,6 +39,7 @@ type DefaultOP struct {
|
|||
|
||||
type Config struct {
|
||||
Issuer string
|
||||
IDTokenValidity time.Duration
|
||||
// ScopesSupported: oidc.SupportedScopes,
|
||||
// ResponseTypesSupported: responseTypes,
|
||||
// GrantTypesSupported: oidc.SupportedGrantTypes,
|
||||
|
@ -172,6 +175,13 @@ func (p *DefaultOP) Signer() Signer {
|
|||
// return
|
||||
}
|
||||
|
||||
func (p *DefaultOP) IDTokenValidity() time.Duration {
|
||||
if p.config.IDTokenValidity == 0 {
|
||||
p.config.IDTokenValidity = DefaultIDTokenValidity
|
||||
}
|
||||
return p.config.IDTokenValidity
|
||||
}
|
||||
|
||||
// func (p *DefaultOP) ErrorHandler() func(w http.ResponseWriter, r *http.Request, authReq *oidc.AuthRequest, err error) {
|
||||
// return AuthRequestError
|
||||
// }
|
||||
|
|
|
@ -58,9 +58,11 @@ func AuthRequestError(w http.ResponseWriter, r *http.Request, authReq ErrAuthReq
|
|||
func ExchangeRequestError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
e, ok := err.(*OAuthError)
|
||||
if !ok {
|
||||
e = new(OAuthError)
|
||||
e.ErrorType = ServerError
|
||||
e.Description = err.Error()
|
||||
}
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshalJSON(w, e)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/gorilla/schema"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
oidc "github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
|
@ -69,6 +70,9 @@ type Sig struct{}
|
|||
func (s *Sig) SignIDToken(*oidc.IDTokenClaims) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (s *Sig) SignatureAlgorithm() jose.SignatureAlgorithm {
|
||||
return jose.HS256
|
||||
}
|
||||
|
||||
func ExpectStorage(a op.Authorizer, t *testing.T) {
|
||||
mockA := a.(*MockAuthorizer)
|
||||
|
|
|
@ -10,11 +10,13 @@ import (
|
|||
|
||||
type Signer interface {
|
||||
SignIDToken(claims *oidc.IDTokenClaims) (string, error)
|
||||
SignatureAlgorithm() jose.SignatureAlgorithm
|
||||
}
|
||||
|
||||
type idTokenSigner struct {
|
||||
signer jose.Signer
|
||||
storage Storage
|
||||
algorithm jose.SignatureAlgorithm
|
||||
}
|
||||
|
||||
func NewDefaultSigner(storage Storage) (Signer, error) {
|
||||
|
@ -36,6 +38,7 @@ func (s *idTokenSigner) initialize() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.algorithm = key.Algorithm
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -46,6 +49,7 @@ func (s *idTokenSigner) SignIDToken(claims *oidc.IDTokenClaims) (string, error)
|
|||
}
|
||||
return s.Sign(payload)
|
||||
}
|
||||
|
||||
func (s *idTokenSigner) Sign(payload []byte) (string, error) {
|
||||
result, err := s.signer.Sign(payload)
|
||||
if err != nil {
|
||||
|
@ -53,3 +57,7 @@ func (s *idTokenSigner) Sign(payload []byte) (string, error) {
|
|||
}
|
||||
return result.CompactSerialize()
|
||||
}
|
||||
|
||||
func (s *idTokenSigner) SignatureAlgorithm() jose.SignatureAlgorithm {
|
||||
return s.algorithm
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package op
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
|
@ -22,6 +24,7 @@ type AuthRequest interface {
|
|||
GetACR() string
|
||||
GetAMR() []string
|
||||
GetAudience() []string
|
||||
GetAuthTime() time.Time
|
||||
GetClientID() string
|
||||
GetNonce() string
|
||||
GetRedirectURI() string
|
||||
|
|
|
@ -5,17 +5,15 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/caos/oidc/pkg/utils"
|
||||
|
||||
"github.com/gorilla/schema"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/utils"
|
||||
)
|
||||
|
||||
type Exchanger interface {
|
||||
Issuer() string
|
||||
IDTokenValidity() time.Duration
|
||||
Storage() Storage
|
||||
Decoder() *schema.Decoder
|
||||
Signer() Signer
|
||||
|
@ -59,7 +57,7 @@ func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
|||
ExchangeRequestError(w, r, err)
|
||||
return
|
||||
}
|
||||
idToken, err := CreateIDToken(exchanger.Issuer(), authReq, "", time.Now(), time.Now(), "", exchanger.Signer())
|
||||
idToken, err := CreateIDToken(exchanger.Issuer(), authReq, exchanger.IDTokenValidity(), accessToken, exchanger.Signer())
|
||||
if err != nil {
|
||||
ExchangeRequestError(w, r, err)
|
||||
return
|
||||
|
@ -76,23 +74,23 @@ func CreateAccessToken() (string, error) {
|
|||
return "accessToken", nil
|
||||
}
|
||||
|
||||
func CreateIDToken(issuer string, authReq AuthRequest, sub string, exp, authTime time.Time, accessToken string, signer Signer) (string, error) {
|
||||
func CreateIDToken(issuer string, authReq AuthRequest, validity time.Duration, accessToken string, signer Signer) (string, error) {
|
||||
var err error
|
||||
exp := time.Now().UTC().Add(validity)
|
||||
claims := &oidc.IDTokenClaims{
|
||||
Issuer: issuer,
|
||||
Subject: authReq.GetSubject(),
|
||||
Audiences: authReq.GetAudience(),
|
||||
Expiration: exp,
|
||||
IssuedAt: time.Now().UTC(),
|
||||
AuthTime: authTime,
|
||||
AuthTime: authReq.GetAuthTime(),
|
||||
Nonce: authReq.GetNonce(),
|
||||
AuthenticationContextClassReference: authReq.GetACR(),
|
||||
AuthenticationMethodsReferences: authReq.GetAMR(),
|
||||
AuthorizedParty: authReq.GetClientID(),
|
||||
}
|
||||
if accessToken != "" {
|
||||
var alg jose.SignatureAlgorithm
|
||||
claims.AccessTokenHash, err = oidc.AccessTokenHash(accessToken, alg) //TODO: alg
|
||||
claims.AccessTokenHash, err = oidc.AccessTokenHash(accessToken, signer.SignatureAlgorithm())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@ const (
|
|||
stateParam = "state"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
||||
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
|
||||
}
|
||||
)
|
||||
|
||||
//DefaultRP impements the `DelegationTokenExchangeRP` interface extending the `RelayingParty` interface
|
||||
type DefaultRP struct {
|
||||
endpoints Endpoints
|
||||
|
@ -30,6 +36,8 @@ type DefaultRP struct {
|
|||
httpClient *http.Client
|
||||
cookieHandler *utils.CookieHandler
|
||||
|
||||
errorHandler func(http.ResponseWriter, *http.Request, string, string, string)
|
||||
|
||||
verifier Verifier
|
||||
}
|
||||
|
||||
|
@ -51,6 +59,10 @@ func NewDefaultRP(rpConfig *Config, rpOpts ...DefaultRPOpts) (DelegationTokenExc
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if p.errorHandler == nil {
|
||||
p.errorHandler = DefaultErrorHandler
|
||||
}
|
||||
|
||||
if p.verifier == nil {
|
||||
p.verifier = NewDefaultVerifier(rpConfig.Issuer, rpConfig.ClientID, NewRemoteKeySet(p.httpClient, p.endpoints.JKWsURL)) //TODO: keys endpoint
|
||||
}
|
||||
|
@ -125,7 +137,10 @@ func (p *DefaultRP) CodeExchangeHandler(callback func(http.ResponseWriter, *http
|
|||
return
|
||||
}
|
||||
params := r.URL.Query()
|
||||
if params.Get("code") != "" {
|
||||
if params.Get("error") != "" {
|
||||
p.errorHandler(w, r, params.Get("error"), params.Get("error_description"), state)
|
||||
return
|
||||
}
|
||||
tokens, err := p.CodeExchange(r.Context(), params.Get("code"))
|
||||
if err != nil {
|
||||
http.Error(w, "failed to exchange token: "+err.Error(), http.StatusUnauthorized)
|
||||
|
@ -133,8 +148,6 @@ func (p *DefaultRP) CodeExchangeHandler(callback func(http.ResponseWriter, *http
|
|||
}
|
||||
callback(w, r, tokens, state)
|
||||
}
|
||||
w.Write([]byte(params.Get("error")))
|
||||
}
|
||||
}
|
||||
|
||||
// func (p *DefaultRP) Introspect(ctx context.Context, accessToken string) (oidc.TokenIntrospectResponse, error) {
|
||||
|
@ -169,18 +182,15 @@ func (p *DefaultRP) DelegationTokenExchange(ctx context.Context, subjectToken st
|
|||
|
||||
func (p *DefaultRP) discover() error {
|
||||
wellKnown := strings.TrimSuffix(p.config.Issuer, "/") + oidc.DiscoveryEndpoint
|
||||
|
||||
req, err := http.NewRequest("GET", wellKnown, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
discoveryConfig := new(oidc.DiscoveryConfiguration)
|
||||
|
||||
err = utils.HttpRequest(p.httpClient, req, &discoveryConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.endpoints = GetEndpoints(discoveryConfig)
|
||||
p.oauthConfig = oauth2.Config{
|
||||
ClientID: p.config.ClientID,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue