Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oauth: use provider-specific key for verification (fixes #248) #249

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## HEAD

### Fixed

* Use provider-specific signing key for verification.

## 1.18.1

### Added
Expand Down
8 changes: 4 additions & 4 deletions app/tokens/oauth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ func (c *Claims) Sign(signingKey jose.SigningKey) (string, error) {

// Parse will deserialize a string into Claims if and only if the claims pass all validations. In
// this case the token must contain a nonce already known from a different channel (like a cookie).
func Parse(tokenStr string, cfg *app.Config, nonce string) (*Claims, error) {
func Parse(tokenStr string, signingKey interface{}, authNURL string, nonce string) (*Claims, error) {
token, err := jwt.ParseSigned(tokenStr)
if err != nil {
return nil, errors.Wrap(err, "ParseSigned")
}

claims := Claims{}
err = token.Claims(cfg.OAuthSigningKey, &claims)
err = token.Claims(signingKey, &claims)
if err != nil {
return nil, errors.Wrap(err, "Claims")
}

err = claims.Claims.Validate(jwt.Expected{
Audience: jwt.Audience{cfg.AuthNURL.String()},
Issuer: cfg.AuthNURL.String(),
Audience: jwt.Audience{authNURL},
Issuer: authNURL,
})
if err != nil {
return nil, errors.Wrap(err, "Validate")
Expand Down
28 changes: 20 additions & 8 deletions app/tokens/oauth/oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,25 @@ func TestOAuthToken(t *testing.T) {
assert.True(t, token.Audience.Contains("https://authn.example.com"))
assert.NotEmpty(t, token.IssuedAt)

tokenStr, err := token.Sign(jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey})
key := jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey}

tokenStr, err := token.Sign(key)
require.NoError(t, err)

_, err = oauth.Parse(tokenStr, cfg, nonce)
_, err = oauth.Parse(tokenStr, key.Key, cfg.AuthNURL.String(), nonce)
require.NoError(t, err)
})

t.Run("parsing with an unknown nonce", func(t *testing.T) {
token, err := oauth.New(cfg, nonce, "https://app.example.com/return")
require.NoError(t, err)

tokenStr, err := token.Sign(jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey})
key := jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey}

tokenStr, err := token.Sign(key)
require.NoError(t, err)

_, err = oauth.Parse(tokenStr, cfg, "wrong")
_, err = oauth.Parse(tokenStr, key.Key, cfg.AuthNURL.String(), "wrong")
assert.Error(t, err)
})

Expand All @@ -52,11 +56,16 @@ func TestOAuthToken(t *testing.T) {
AuthNURL: cfg.AuthNURL,
OAuthSigningKey: []byte("old-a-reno"),
}
oldKey := jose.SigningKey{Algorithm: jose.HS256, Key: oldCfg.OAuthSigningKey}

token, err := oauth.New(cfg, nonce, "https://app.example.com/return")
require.NoError(t, err)
tokenStr, err := token.Sign(jose.SigningKey{Algorithm: jose.HS256, Key: oldCfg.OAuthSigningKey})

tokenStr, err := token.Sign(oldKey)
require.NoError(t, err)
_, err = oauth.Parse(tokenStr, cfg, nonce)

key := jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey}
_, err = oauth.Parse(tokenStr, key.Key, cfg.AuthNURL.String(), nonce)
assert.Error(t, err)
})

Expand All @@ -67,9 +76,12 @@ func TestOAuthToken(t *testing.T) {
}
token, err := oauth.New(&oldCfg, nonce, "https://app.example.com/return")
require.NoError(t, err)
tokenStr, err := token.Sign(jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey})

key := jose.SigningKey{Algorithm: jose.HS256, Key: cfg.OAuthSigningKey}

tokenStr, err := token.Sign(key)
require.NoError(t, err)
_, err = oauth.Parse(tokenStr, cfg, nonce)
_, err = oauth.Parse(tokenStr, key.Key, cfg.AuthNURL.String(), nonce)
assert.Error(t, err)
})
}
4 changes: 2 additions & 2 deletions server/handlers/get_oauth_return.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func GetOauthReturn(app *app.App, providerName string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
provider := app.OauthProviders[providerName]

// verify the state and nonce
state, err := getState(app.Config, r)
// verify the state and nonce using the key associated with the provider's signing key.
state, err := getState(app.Config, r, provider.SigningKey().Key)
if err != nil {
app.Reporter.ReportRequestError(errors.Wrap(err, "getState"), r)
failsafe := app.Config.ApplicationDomains[0].URL()
Expand Down
4 changes: 2 additions & 2 deletions server/handlers/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ func nonceCookie(cfg *app.Config, val string) *http.Cookie {
}

// getState returns a verified state token using the nonce cookie
func getState(cfg *app.Config, r *http.Request) (*oauth.Claims, error) {
func getState(cfg *app.Config, r *http.Request, verificationKey interface{}) (*oauth.Claims, error) {
nonce, err := r.Cookie(cfg.OAuthCookieName)
if err != nil {
return nil, errors.Wrap(err, "Cookie")
}
state, err := oauth.Parse(r.FormValue("state"), cfg, nonce.Value)
state, err := oauth.Parse(r.FormValue("state"), verificationKey, cfg.AuthNURL.String(), nonce.Value)
if err != nil {
return nil, errors.Wrap(err, "Parse")
}
Expand Down
Loading