Skip to content

Commit

Permalink
Merge pull request #9 from canonical/IAM-820
Browse files Browse the repository at this point in the history
fix: validate user code has not expired
  • Loading branch information
nsklikas authored Apr 10, 2024
2 parents d80cc46 + 372c4aa commit bef13a4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
17 changes: 11 additions & 6 deletions consent/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,11 @@ func (h *Handler) acceptUserCodeRequest(w http.ResponseWriter, r *http.Request,
return
}

if reqBody.UserCode == "" {
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Field 'user_code' must not be empty.")))
return
}

cr, err := h.r.ConsentManager().GetDeviceUserAuthRequest(ctx, challenge)
if err != nil {
h.r.Writer().WriteError(w, r, errorsx.WithStack(err))
Expand All @@ -1103,21 +1108,21 @@ func (h *Handler) acceptUserCodeRequest(w http.ResponseWriter, r *http.Request,
return
}

if reqBody.UserCode == "" {
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Field 'user_code' must not be empty.")))
return
}

userCodeSignature, err := h.r.RFC8628HMACStrategy().UserCodeSignature(r.Context(), reqBody.UserCode)
if err != nil {
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithHint(`'user_code' signature could not be computed`)))
return
}
userCodeRequest, err := h.r.OAuth2Storage().GetUserCodeSession(r.Context(), userCodeSignature, &fosite.DefaultSession{})
userCodeRequest, err := h.r.OAuth2Storage().GetUserCodeSession(r.Context(), userCodeSignature, nil)
if err != nil {
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrNotFound.WithWrap(err).WithHint(`'user_code' session not found`)))
return
}
err = h.r.RFC8628HMACStrategy().ValidateUserCode(ctx, userCodeRequest, reqBody.UserCode)
if err != nil {
h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrTokenExpired.WithWrap(err).WithHint(`'user_code' has expired`)))
return
}

err = h.r.OAuth2Storage().UpdateAndInvalidateUserCodeSession(r.Context(), userCodeSignature, f.ID)
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions consent/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/stretchr/testify/require"

"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/jwt"
hydra "github.com/ory/hydra-client-go/v2"
"github.com/ory/hydra/v2/client"
. "github.com/ory/hydra/v2/consent"
Expand Down Expand Up @@ -529,6 +531,37 @@ func TestAcceptCodeDeviceRequestFailure(t *testing.T) {
require.EqualValues(t, http.StatusNotFound, resp.StatusCode)
},
},
{
desc: "expired user_code",
getBody: func() ([]byte, error) {
deviceRequest := fosite.NewDeviceRequest()
deviceRequest.Client = cl
userCode, sig, err := reg.RFC8628HMACStrategy().GenerateUserCode(ctx)
require.NoError(t, err)
deviceRequest.SetSession(
&oauth2.Session{
DefaultSession: &openid.DefaultSession{
Headers: &jwt.Headers{},
},
BrowserFlowCompleted: false,
},
)
exp := time.Now().UTC()
deviceRequest.Session.SetExpiresAt(fosite.UserCode, exp)
err = reg.OAuth2Storage().CreateUserCodeSession(ctx, sig, deviceRequest)
require.NoError(t, err)
return json.Marshal(&hydra.AcceptDeviceUserCodeRequest{UserCode: &userCode})
},
getURL: func() string {
return ts.URL + "/admin" + DevicePath + "/accept?challenge=" + challenge
},
validateResponse: func(resp *http.Response) {
require.EqualValues(t, http.StatusUnauthorized, resp.StatusCode)
result := &fosite.RFC6749Error{}
require.NoError(t, json.NewDecoder(resp.Body).Decode(&result))
require.EqualValues(t, result.ErrorField, fosite.ErrTokenExpired.ErrorField)
},
},
{
desc: "extra fields",
getBody: func() ([]byte, error) {
Expand Down
3 changes: 3 additions & 0 deletions persistence/sql/persister_oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,9 @@ func (p *Persister) CreateUserCodeSession(ctx context.Context, signature string,
func (p *Persister) GetUserCodeSession(ctx context.Context, signature string, session fosite.Session) (_ fosite.Requester, err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetUserCodeSession")
defer otelx.End(span, &err)
if session == nil {
session = oauth2.NewSession("")
}
return p.findSessionBySignature(ctx, signature, session, sqlTableUserCode)
}

Expand Down

0 comments on commit bef13a4

Please sign in to comment.