feat: validate id_token in auth code flow

Co-authored-by: Kent Daleng <kent.daleng@nav.no>
This commit is contained in:
Trong Huu Nguyen
2021-08-23 09:59:15 +02:00
parent 83b7eb65b0
commit f36848babe
5 changed files with 81 additions and 13 deletions

View File

@@ -1,15 +1,19 @@
package main
import (
"context"
"net/http"
"os"
"github.com/coreos/go-oidc"
"github.com/nais/liberator/pkg/conftools"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"github.com/nais/wonderwall/pkg/config"
"github.com/nais/wonderwall/pkg/cryptutil"
"github.com/nais/wonderwall/pkg/logging"
"github.com/nais/wonderwall/pkg/router"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"net/http"
"os"
)
var maskedConfig = []string{
@@ -59,6 +63,11 @@ func run() error {
Crypter: crypt,
OauthConfig: oauthConfig,
UpstreamHost: cfg.UpstreamHost,
IdTokenVerifier: oidc.NewVerifier(
cfg.IDPorten.WellKnown.Issuer,
oidc.NewRemoteKeySet(context.Background(), cfg.IDPorten.WellKnown.JwksURI),
&oidc.Config{ClientID: cfg.IDPorten.ClientID},
),
}
handler.Init()

1
go.mod
View File

@@ -3,6 +3,7 @@ module github.com/nais/wonderwall
go 1.16
require (
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/go-chi/chi v1.5.4
github.com/nais/liberator v0.0.0-20210809103005-edb0141d646d
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect

2
go.sum
View File

@@ -80,6 +80,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -374,6 +375,7 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=

27
pkg/auth/validate.go Normal file
View File

@@ -0,0 +1,27 @@
package auth
import (
"context"
"fmt"
"github.com/coreos/go-oidc"
"golang.org/x/oauth2"
)
func ValidateIdToken(ctx context.Context, verifier *oidc.IDTokenVerifier, token *oauth2.Token, nonce string) error {
raw, ok := token.Extra("id_token").(string)
if !ok {
return fmt.Errorf("missing id_token in token response")
}
idToken, err := verifier.Verify(ctx, raw)
if err != nil {
return err
}
if idToken.Nonce != nonce {
return fmt.Errorf("nonce does not match")
}
return nil
}

View File

@@ -7,18 +7,23 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/go-chi/chi/middleware"
"github.com/nais/wonderwall/pkg/cryptutil"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"net/url"
"time"
"github.com/coreos/go-oidc"
"github.com/go-chi/chi/middleware"
log "github.com/sirupsen/logrus"
"github.com/nais/wonderwall/pkg/auth"
"github.com/nais/wonderwall/pkg/cryptutil"
"github.com/go-chi/chi"
"github.com/nais/wonderwall/pkg/config"
"golang.org/x/oauth2"
"gopkg.in/square/go-jose.v2"
"github.com/nais/wonderwall/pkg/config"
)
const (
@@ -26,15 +31,17 @@ const (
ScopeOpenID = "openid"
SessionCookieName = "io.nais.wonderwall.session"
StateCookieName = "io.nais.wonderwall.state"
NonceCookieName = "io.nais.wonderwall.nonce"
CodeVerifierCookieName = "io.nais.wonderwall.code_verifier"
)
type Handler struct {
Config config.IDPorten
OauthConfig oauth2.Config
Crypter cryptutil.Crypter
UpstreamHost string
sessions map[string]*oauth2.Token
Config config.IDPorten
OauthConfig oauth2.Config
Crypter cryptutil.Crypter
UpstreamHost string
IdTokenVerifier *oidc.IDTokenVerifier
sessions map[string]*oauth2.Token
}
type loginParams struct {
@@ -42,6 +49,7 @@ type loginParams struct {
state string
codeVerifier string
url string
nonce string
}
func (h *Handler) Init() {
@@ -102,6 +110,7 @@ func (h *Handler) LoginURL() (*loginParams, error) {
return &loginParams{
session: base64.RawURLEncoding.EncodeToString(session),
state: base64.RawURLEncoding.EncodeToString(state),
nonce: base64.RawURLEncoding.EncodeToString(nonce),
codeVerifier: string(codeVerifier),
url: u.String(),
}, nil
@@ -129,6 +138,12 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
return
}
err = h.setEncryptedCookie(w, NonceCookieName, params.nonce)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
err = h.setEncryptedCookie(w, CodeVerifierCookieName, params.codeVerifier)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
@@ -228,6 +243,13 @@ func (h *Handler) Callback(w http.ResponseWriter, r *http.Request) {
return
}
nonce, err := h.getEncryptedCookie(r, NonceCookieName)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
codeVerifier, err := h.getEncryptedCookie(r, CodeVerifierCookieName)
if err != nil {
log.Error(err)
@@ -268,6 +290,13 @@ func (h *Handler) Callback(w http.ResponseWriter, r *http.Request) {
return
}
err = auth.ValidateIdToken(r.Context(), h.IdTokenVerifier, token, nonce)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
h.sessions[sessionCookie.Value] = token
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)