Skip to content

Commit

Permalink
0.5.0 (ory#119)
Browse files Browse the repository at this point in the history
* all: resolve regression issues introduced by 0.4.0 - closes ory#118
* oauth2: introspection handler excess calls - closes ory#117
* oauth2: inaccurate expires_in time - closes ory#72
  • Loading branch information
arekkas authored Oct 17, 2016
1 parent 1041e67 commit eb9077f
Show file tree
Hide file tree
Showing 66 changed files with 453 additions and 389 deletions.
14 changes: 14 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
This is a list of breaking changes. As long as `1.0.0` is not released, breaking changes will be addressed as minor version
bumps (`0.1.0` -> `0.2.0`).

## 0.5.0

Breaking changes:

* `compose.OpenIDConnectExplicit` is now `compose.OpenIDConnectExplicitFactory`
* `compose.OpenIDConnectImplicit` is now `compose.OpenIDConnectImplicitFactory`
* `compose.OpenIDConnectHybrid` is now `compose.OpenIDConnectHybridFactory`
* The token introspection handler is no longer added automatically by `compose.OAuth2*`. Add `compose.OAuth2TokenIntrospectionFactory`
to your composer if you need token introspection.
* Session refactor:
* The HMACSessionContainer was removed and replaced by `fosite.Session` / `fosite.DefaultSession`. All sessions
must now implement this signature. The new session interface allows for better expiration time handling.
* The OpenID `DefaultSession` signature changed as well, it is now implementing the `fosite.Session` interface

## 0.4.0

Breaking changes:
Expand Down
26 changes: 8 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,20 +202,6 @@ var config = compose.Config {

var oauth2Provider = compose.ComposeAllEnabled(config *Config, storage, secret, privateKey)

// The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests.
// The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the
// session struct can be anything you want it to be.
type session struct {
UserID string
Foobar int

// this is used in the OAuth2 handlers. You can set per-session expiry times here, for example.
*oauth2Strat.HMACSession

// this is used by the OpenID connect handlers. You can set custom id token headers and claims.
*oidcStrat.DefaultSession
}

// The authorize endpoint is usually at "https://mydomain.com/oauth2/auth".
func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
// This context will be passed to all methods. It doesn't fulfill a real purpose in the standard library but could be used
Expand Down Expand Up @@ -247,8 +233,12 @@ func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {

// Now that the user is authorized, we set up a session. When validating / looking up tokens, we additionally get
// the session. You can store anything you want in it.
mySessionData := &session{
UserID: req.Form.Get("username")

// The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests.
// The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the
// session struct can be anything you want it to be.
mySessionData := &fosite.DefaultSession{
Username: req.Form.Get("username")
}

// It's also wise to check the requested scopes, e.g.:
Expand All @@ -273,7 +263,7 @@ func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
// The token endpoint is usually at "https://mydomain.com/oauth2/token"
func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) {
ctx := NewContext()
mySessionData := &session{}
mySessionData := new(fosite.DefaultSession)

// This will create an access request object and iterate through the registered TokenEndpointHandlers to validate the request.
accessRequest, err := oauth2.NewAccessRequest(ctx, req, mySessionData)
Expand Down Expand Up @@ -302,7 +292,7 @@ func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) {

func someResourceProviderHandlerFunc(rw http.ResponseWriter, req *http.Request) {
ctx := NewContext()
mySessionData := &session{}
mySessionData := new(fosite.DefaultSession)
requiredScope := "blogposts.create"

ar, err := oauth2.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), mySessionData, requiredScope)
Expand Down
2 changes: 1 addition & 1 deletion access_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type AccessRequest struct {
Request
}

func NewAccessRequest(session interface{}) *AccessRequest {
func NewAccessRequest(session Session) *AccessRequest {
r := &AccessRequest{
GrantTypes: Arguments{},
HandledGrantType: Arguments{},
Expand Down
2 changes: 1 addition & 1 deletion access_request_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
// credentials (or assigned other authentication requirements), the
// client MUST authenticate with the authorization server as described
// in Section 3.2.1.
func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session interface{}) (AccessRequester, error) {
func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session Session) (AccessRequester, error) {
accessRequest := NewAccessRequest(session)

if r.Method != "POST" {
Expand Down
2 changes: 1 addition & 1 deletion access_request_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func TestNewAccessRequest(t *testing.T) {
c.mock()
ctx := NewContext()
fosite.TokenEndpointHandlers = c.handlers
ar, err := fosite.NewAccessRequest(ctx, r, &struct{}{})
ar, err := fosite.NewAccessRequest(ctx, r, new(DefaultSession))
assert.True(t, errors.Cause(err) == c.expectErr, "%d\nwant: %s \ngot: %s", k, c.expectErr, err)
if err != nil {
t.Logf("Error occured: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion access_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (a *AccessResponse) SetScopes(scopes Arguments) {
}

func (a *AccessResponse) SetExpiresIn(expiresIn time.Duration) {
a.SetExtra("expires_in", strconv.Itoa(int(expiresIn)))
a.SetExtra("expires_in", strconv.FormatInt(int64(expiresIn/time.Second), 10))
}

func (a *AccessResponse) SetExtra(key string, value interface{}) {
Expand Down
4 changes: 2 additions & 2 deletions authorize_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ func TestAuthorizeRequest(t *testing.T) {
assert.Equal(t, c.isRedirValid, c.ar.IsRedirectURIValid(), "%d", k)

c.ar.GrantScope("foo")
c.ar.SetSession(&struct{}{})
c.ar.SetSession(&DefaultSession{})
c.ar.SetRequestedScopes([]string{"foo"})
assert.True(t, c.ar.GetGrantedScopes().Has("foo"))
assert.True(t, c.ar.GetRequestedScopes().Has("foo"))
assert.Equal(t, &struct{}{}, c.ar.GetSession())
assert.Equal(t, &DefaultSession{}, c.ar.GetSession())
}
}
2 changes: 1 addition & 1 deletion authorize_response_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"golang.org/x/net/context"
)

func (o *Fosite) NewAuthorizeResponse(ctx context.Context, r *http.Request, ar AuthorizeRequester, session interface{}) (AuthorizeResponder, error) {
func (o *Fosite) NewAuthorizeResponse(ctx context.Context, r *http.Request, ar AuthorizeRequester, session Session) (AuthorizeResponder, error) {
var resp = &AuthorizeResponse{
Header: http.Header{},
Query: url.Values{},
Expand Down
4 changes: 2 additions & 2 deletions authorize_response_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestNewAuthorizeResponse(t *testing.T) {
duo := &Fosite{
AuthorizeEndpointHandlers: AuthorizeEndpointHandlers{handlers[0], handlers[0]},
}
ar.EXPECT().SetSession(gomock.Eq(struct{}{})).AnyTimes()
ar.EXPECT().SetSession(gomock.Eq(new(DefaultSession))).AnyTimes()
fooErr := errors.New("foo")
for k, c := range []struct {
isErr bool
Expand Down Expand Up @@ -66,7 +66,7 @@ func TestNewAuthorizeResponse(t *testing.T) {
},
} {
c.mock()
responder, err := oauth2.NewAuthorizeResponse(ctx, &http.Request{}, ar, struct{}{})
responder, err := oauth2.NewAuthorizeResponse(ctx, &http.Request{}, ar, new(DefaultSession))
assert.Equal(t, c.isErr, err != nil, "%d: %s", k, err)
if err != nil {
assert.Equal(t, c.expectErr, err, "%d: %s", k, err)
Expand Down
8 changes: 5 additions & 3 deletions compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ func ComposeAllEnabled(config *Config, storage interface{}, secret []byte, key *
OAuth2RefreshTokenGrantFactory,
OAuth2ResourceOwnerPasswordCredentialsFactory,

OpenIDConnectExplicit,
OpenIDConnectImplicit,
OpenIDConnectHybrid,
OpenIDConnectExplicitFactory,
OpenIDConnectImplicitFactory,
OpenIDConnectHybridFactory,

OAuth2TokenIntrospectionFactory,
)
}
142 changes: 43 additions & 99 deletions compose/compose_oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,138 +8,82 @@ import (
// OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2AuthorizeExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &struct {
// register the handler
*oauth2.AuthorizeExplicitGrantHandler

// also register the validator for access tokens
*oauth2.CoreValidator
}{
AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy),
AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
AuthCodeLifespan: config.GetAuthorizeCodeLifespan(),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
CoreValidator: &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
return &oauth2.AuthorizeExplicitGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy),
AuthorizeCodeGrantStorage: storage.(oauth2.AuthorizeCodeGrantStorage),
AuthCodeLifespan: config.GetAuthorizeCodeLifespan(),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
}

// OAuth2ClientCredentialsGrantFactory creates an OAuth2 client credentials grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2ClientCredentialsGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &struct {
// register the handler
*oauth2.ClientCredentialsGrantHandler

// also register the validator for access tokens
*oauth2.CoreValidator
}{
ClientCredentialsGrantHandler: &oauth2.ClientCredentialsGrantHandler{
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
CoreValidator: &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
return &oauth2.ClientCredentialsGrantHandler{
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
}

// OAuth2RefreshTokenGrantFactory creates an OAuth2 refresh grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2RefreshTokenGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &struct {
// register the handler
*oauth2.RefreshTokenGrantHandler

// also register the validator for access tokens
*oauth2.CoreValidator
}{
RefreshTokenGrantHandler: &oauth2.RefreshTokenGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
RefreshTokenGrantStorage: storage.(oauth2.RefreshTokenGrantStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
CoreValidator: &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
return &oauth2.RefreshTokenGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
RefreshTokenGrantStorage: storage.(oauth2.RefreshTokenGrantStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
}
}

// OAuth2AuthorizeImplicitFactory creates an OAuth2 implicit grant ("authorize implicit flow") handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2AuthorizeImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &struct {
// register the handler
*oauth2.AuthorizeImplicitGrantTypeHandler

// also register the validator for access tokens
*oauth2.CoreValidator
}{
AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
CoreValidator: &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
return &oauth2.AuthorizeImplicitGrantTypeHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
}

// OAuth2ResourceOwnerPasswordCredentialsFactory creates an OAuth2 resource owner password credentials grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2ResourceOwnerPasswordCredentialsFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &struct {
// register the handler
*oauth2.ResourceOwnerPasswordCredentialsGrantHandler

// also register the validator for access tokens
*oauth2.CoreValidator
}{
ResourceOwnerPasswordCredentialsGrantHandler: &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{
ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage),
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
ScopeStrategy: fosite.HierarchicScopeStrategy,
},
CoreValidator: &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
return &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{
ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage),
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
}

// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler and registers
// an access token, refresh token and authorize code validator.
// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler.
func OAuth2TokenRevocationFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.TokenRevocationHandler{
TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage),
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
}
}

// OAuth2TokenIntrospectionFactory creates an OAuth2 token introspection handler and registers
// an access token and refresh token validator.
func OAuth2TokenIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
}
Loading

0 comments on commit eb9077f

Please sign in to comment.