Skip to content

Commit

Permalink
Implement support for token reuse detection in fosite
Browse files Browse the repository at this point in the history
  • Loading branch information
svrakitin committed Mar 8, 2021
1 parent b46a14c commit 39bcce6
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 32 deletions.
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/gobuffalo/pop/v5 v5.3.1
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7
github.com/gobwas/glob v0.2.3
github.com/golang/mock v1.4.3
github.com/golang/mock v1.4.4
github.com/google/uuid v1.1.1
github.com/gorilla/securecookie v1.1.1
github.com/gorilla/sessions v1.2.0
Expand All @@ -39,7 +39,7 @@ require (
github.com/olekukonko/tablewriter v0.0.1
github.com/ory/analytics-go/v4 v4.0.1
github.com/ory/cli v0.0.35
github.com/ory/fosite v0.36.0
github.com/ory/fosite v0.39.0
github.com/ory/go-acc v0.2.6
github.com/ory/graceful v0.1.1
github.com/ory/herodot v0.9.1
Expand All @@ -54,14 +54,13 @@ require (
github.com/sawadashota/encrypta v0.0.2
github.com/sirupsen/logrus v1.6.0
github.com/spf13/cobra v1.0.0
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 // indirect
github.com/stretchr/testify v1.6.1
github.com/tidwall/gjson v1.6.7
github.com/toqueteos/webbrowser v1.2.0
github.com/uber/jaeger-lib v2.4.0+incompatible // indirect
github.com/urfave/negroni v1.0.0
go.uber.org/automaxprocs v1.3.0
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/tools v0.0.0-20201019175715-b894a3290fff
Expand Down
17 changes: 8 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -559,8 +559,8 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -957,8 +957,8 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh
github.com/ory/dockertest/v3 v3.5.4 h1:rYijlJuraj8D4OgC1DpYpCV8SGXrkviT3RVrjFy7OFc=
github.com/ory/dockertest/v3 v3.5.4/go.mod h1:J8ZUbNB2FOhm1cFZW9xBpDsODqsSWcyYgtJYVPcnF70=
github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0=
github.com/ory/fosite v0.36.0 h1:6XGd9sE0h/y6XJx3L3iRm/UFPHVEnARQch0YFxvxziQ=
github.com/ory/fosite v0.36.0/go.mod h1:NE15bS1ya8E4J8VmminFY+nsZdoBQu+5/vGF2ELvDsY=
github.com/ory/fosite v0.39.0 h1:u1Ct/ME7XYzREvufr7ehBIdq/KatjVLIYg/ABqWzprw=
github.com/ory/fosite v0.39.0/go.mod h1:37r59qkOSPueYKmaA7EHiXrDMF1B+XPN+MgkZgTRg3Y=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/go-acc v0.2.6 h1:YfI+L9dxI7QCtWn2RbawqO0vXhiThdXu/RgizJBbaq0=
Expand Down Expand Up @@ -1312,8 +1312,8 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -1460,7 +1460,8 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
Expand Down Expand Up @@ -1675,5 +1676,3 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
10 changes: 6 additions & 4 deletions oauth2/fosite_store_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,13 @@ func testHelperRevokeRefreshToken(x InternalRegistry) func(t *testing.T) {
err = m.RevokeRefreshToken(ctx, reqIdTwo)
require.NoError(t, err)

_, err = m.GetRefreshTokenSession(ctx, "1111", &Session{})
assert.NotNil(t, err)
req, err := m.GetRefreshTokenSession(ctx, "1111", &Session{})
assert.NotNil(t, req)
assert.EqualError(t, err, fosite.ErrInactiveToken.Error())

_, err = m.GetRefreshTokenSession(ctx, "1122", &Session{})
assert.NotNil(t, err)
req, err = m.GetRefreshTokenSession(ctx, "1122", &Session{})
assert.NotNil(t, req)
assert.EqualError(t, err, fosite.ErrInactiveToken.Error())

}
}
Expand Down
16 changes: 13 additions & 3 deletions oauth2/oauth2_auth_code_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -899,16 +899,26 @@ func TestAuthCodeWithMockStrategy(t *testing.T) {
assert.EqualValues(t, http.StatusUnauthorized, res.StatusCode)
})

t.Run("refreshing new refresh token should work", func(t *testing.T) {
res, err := testRefresh(t, &refreshedToken, ts.URL, false)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)

body, err := ioutil.ReadAll(res.Body)
require.NoError(t, err)
require.NoError(t, json.Unmarshal(body, &refreshedToken))
})

t.Run("refreshing old token should no longer work", func(t *testing.T) {
res, err := testRefresh(t, token, ts.URL, false)
require.NoError(t, err)
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
assert.Equal(t, http.StatusUnauthorized, res.StatusCode)
})

t.Run("refreshing new refresh token should work", func(t *testing.T) {
t.Run("attempt to refresh old token should revoke new token", func(t *testing.T) {
res, err := testRefresh(t, &refreshedToken, ts.URL, false)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
assert.Equal(t, http.StatusUnauthorized, res.StatusCode)
})

t.Run("duplicate code exchange fails", func(t *testing.T) {
Expand Down
36 changes: 24 additions & 12 deletions persistence/sql/persister_oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,23 +231,23 @@ func (p *Persister) findSessionBySignature(ctx context.Context, rawSignature str
return errorsx.WithStack(fosite.ErrNotFound)
} else if err != nil {
return sqlcon.HandleError(err)
} else if !r.Active && table == sqlTableCode {
} else if !r.Active {
fr, err = r.toRequest(ctx, session, p)
if err != nil {
return err
} else {
} else if table == sqlTableCode {
return errorsx.WithStack(fosite.ErrInvalidatedAuthorizeCode)
} else if table == sqlTableRefresh {
return errorsx.WithStack(fosite.ErrInactiveToken)
}
} else if !r.Active {
return errorsx.WithStack(fosite.ErrInactiveToken)
}

fr, err = r.toRequest(ctx, session, p)
return err
})
}

func (p *Persister) deleteSession(ctx context.Context, signature string, table tableName) error {
func (p *Persister) deleteSessionBySignature(ctx context.Context, signature string, table tableName) error {
signature = p.hashSignature(signature, table)

/* #nosec G201 table is static */
Expand All @@ -257,7 +257,7 @@ func (p *Persister) deleteSession(ctx context.Context, signature string, table t
Exec())
}

func (p *Persister) revokeSession(ctx context.Context, id string, table tableName) error {
func (p *Persister) deleteSessionByRequestID(ctx context.Context, id string, table tableName) error {
/* #nosec G201 table is static */
if err := p.Connection(ctx).RawQuery(
fmt.Sprintf("DELETE FROM %s WHERE request_id=?", OAuth2RequestSQL{Table: table}.TableName()),
Expand All @@ -275,6 +275,18 @@ func (p *Persister) revokeSession(ctx context.Context, id string, table tableNam
return nil
}

func (p *Persister) deactivateSessionByRequestID(ctx context.Context, id string, table tableName) error {
/* #nosec G201 table is static */
return sqlcon.HandleError(
p.Connection(ctx).
RawQuery(
fmt.Sprintf("UPDATE %s SET active=false WHERE request_id=?", OAuth2RequestSQL{Table: table}.TableName()),
id,
).
Exec(),
)
}

func (p *Persister) CreateAuthorizeCodeSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
return p.createSession(ctx, signature, requester, sqlTableCode)
}
Expand Down Expand Up @@ -302,7 +314,7 @@ func (p *Persister) GetAccessTokenSession(ctx context.Context, signature string,
}

func (p *Persister) DeleteAccessTokenSession(ctx context.Context, signature string) (err error) {
return p.deleteSession(ctx, signature, sqlTableAccess)
return p.deleteSessionBySignature(ctx, signature, sqlTableAccess)
}

func (p *Persister) CreateRefreshTokenSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
Expand All @@ -314,7 +326,7 @@ func (p *Persister) GetRefreshTokenSession(ctx context.Context, signature string
}

func (p *Persister) DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) {
return p.deleteSession(ctx, signature, sqlTableRefresh)
return p.deleteSessionBySignature(ctx, signature, sqlTableRefresh)
}

func (p *Persister) CreateOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) error {
Expand All @@ -326,7 +338,7 @@ func (p *Persister) GetOpenIDConnectSession(ctx context.Context, signature strin
}

func (p *Persister) DeleteOpenIDConnectSession(ctx context.Context, signature string) error {
return p.deleteSession(ctx, signature, sqlTableOpenID)
return p.deleteSessionBySignature(ctx, signature, sqlTableOpenID)
}

func (p *Persister) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) {
Expand All @@ -338,15 +350,15 @@ func (p *Persister) CreatePKCERequestSession(ctx context.Context, signature stri
}

func (p *Persister) DeletePKCERequestSession(ctx context.Context, signature string) error {
return p.deleteSession(ctx, signature, sqlTablePKCE)
return p.deleteSessionBySignature(ctx, signature, sqlTablePKCE)
}

func (p *Persister) RevokeRefreshToken(ctx context.Context, id string) error {
return p.revokeSession(ctx, id, sqlTableRefresh)
return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh)
}

func (p *Persister) RevokeAccessToken(ctx context.Context, id string) error {
return p.revokeSession(ctx, id, sqlTableAccess)
return p.deleteSessionByRequestID(ctx, id, sqlTableAccess)
}

func (p *Persister) FlushInactiveAccessTokens(ctx context.Context, notAfter time.Time) error {
Expand Down

0 comments on commit 39bcce6

Please sign in to comment.