refactor: clean up id_token validation

This commit is contained in:
Trong Huu Nguyen
2021-08-25 08:22:34 +02:00
parent f414470910
commit 03a14eb2bd
9 changed files with 156 additions and 110 deletions

View File

@@ -4,14 +4,16 @@ import (
"context"
"encoding/base64"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/nais/wonderwall/pkg/session"
"net/http"
"os"
"github.com/go-redis/redis/v8"
"github.com/lestrrat-go/jwx/jwk"
"github.com/nais/wonderwall/pkg/session"
"github.com/nais/wonderwall/pkg/token"
"github.com/coreos/go-oidc"
"github.com/nais/liberator/pkg/conftools"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
@@ -88,6 +90,11 @@ func run() error {
Scopes: scopes,
}
jwkSet, err := jwk.Fetch(context.Background(), cfg.IDPorten.WellKnown.JwksURI)
if err != nil {
return fmt.Errorf("fetching jwks: %w", err)
}
handler := &router.Handler{
Config: cfg.IDPorten,
Crypter: crypt,
@@ -95,11 +102,7 @@ func run() error {
UpstreamHost: cfg.UpstreamHost,
SecureCookies: true,
Sessions: sessionStore,
IdTokenVerifier: oidc.NewVerifier(
cfg.IDPorten.WellKnown.Issuer,
oidc.NewRemoteKeySet(context.Background(), cfg.IDPorten.WellKnown.JwksURI),
&oidc.Config{ClientID: cfg.IDPorten.ClientID},
),
JwkSet: jwkSet,
}
r := router.New(handler)

4
go.mod
View File

@@ -3,8 +3,6 @@ module github.com/nais/wonderwall
go 1.16
require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/go-chi/chi v1.5.4
github.com/go-redis/redis/v8 v8.11.3
github.com/google/uuid v1.1.2
@@ -15,9 +13,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
go.opentelemetry.io/otel v0.6.0 // indirect
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
golang.org/x/text v0.3.6 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/square/go-jose.v2 v2.6.0
)

20
go.sum
View File

@@ -47,9 +47,7 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -66,15 +64,12 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -87,7 +82,6 @@ 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=
@@ -245,8 +239,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -391,6 +385,7 @@ github.com/nais/liberator v0.0.0-20210809103005-edb0141d646d/go.mod h1:Dw7TPRYZk
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -398,14 +393,15 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -421,7 +417,6 @@ 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=
@@ -448,7 +443,6 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
@@ -509,7 +503,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -614,7 +607,6 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
@@ -826,7 +818,6 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
@@ -897,7 +888,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
@@ -911,13 +901,13 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

View File

@@ -1,27 +0,0 @@
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) (*oidc.IDToken, error) {
raw, ok := token.Extra("id_token").(string)
if !ok {
return nil, fmt.Errorf("missing id_token in token response")
}
idToken, err := verifier.Verify(ctx, raw)
if err != nil {
return nil, err
}
if idToken.Nonce != nonce {
return nil, fmt.Errorf("nonce does not match")
}
return idToken, nil
}

30
pkg/keyset/keyset.go Normal file
View File

@@ -0,0 +1,30 @@
package keyset
import (
"context"
"fmt"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
)
// EnsureValid sets fields for the keys in the given keyset if missing.
// We only accept keys with the "alg" value set to RS256.
func EnsureValid(ctx context.Context, jwks jwk.Set) error {
for iter := jwks.Iterate(ctx); iter.Next(ctx); {
pair := iter.Pair()
key := pair.Value.(jwk.Key)
if len(key.Algorithm()) == 0 {
err := key.Set(jwk.AlgorithmKey, jwa.RS256)
if err != nil {
return fmt.Errorf("setting key algorithm")
}
}
if key.Algorithm() != string(jwa.RS256) {
jwks.Remove(key)
}
}
return nil
}

View File

@@ -41,6 +41,16 @@ func NewIDPorten(clients map[string]string) *IDPorten {
panic(err)
}
err = jwk.AssignKeyID(key)
if err != nil {
panic(err)
}
err = key.Set(jwk.AlgorithmKey, jwa.RS256)
if err != nil {
panic(err)
}
keys := jwk.NewSet()
keys.Add(key)

View File

@@ -6,27 +6,24 @@ import (
"crypto/sha256"
"encoding/base64"
"fmt"
"github.com/nais/wonderwall/pkg/session"
"gopkg.in/square/go-jose.v2/jwt"
"io"
"net/http"
"net/url"
"sync"
"time"
"github.com/coreos/go-oidc"
"github.com/nais/wonderwall/pkg/token"
"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"
"golang.org/x/oauth2"
"github.com/lestrrat-go/jwx/jwt"
"github.com/nais/wonderwall/pkg/config"
"github.com/nais/wonderwall/pkg/cryptutil"
"github.com/nais/wonderwall/pkg/session"
"github.com/nais/wonderwall/pkg/token"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/lestrrat-go/jwx/jwk"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
)
const (
@@ -39,14 +36,14 @@ const (
)
type Handler struct {
Config config.IDPorten
OauthConfig oauth2.Config
Crypter cryptutil.Crypter
UpstreamHost string
IdTokenVerifier *oidc.IDTokenVerifier
SecureCookies bool
Sessions session.Store
lock sync.Mutex
Config config.IDPorten
OauthConfig oauth2.Config
Crypter cryptutil.Crypter
UpstreamHost string
JwkSet jwk.Set
SecureCookies bool
Sessions session.Store
lock sync.Mutex
}
type loginParams struct {
@@ -112,6 +109,7 @@ func (h *Handler) LoginURL() (*loginParams, error) {
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
params, err := h.LoginURL()
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@@ -122,6 +120,7 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
NewCookie(CodeVerifierCookieName, params.codeVerifier, LoginCookieLifetime),
)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@@ -170,32 +169,35 @@ func (h *Handler) Callback(w http.ResponseWriter, r *http.Request) {
return
}
idToken, err := auth.ValidateIdToken(r.Context(), h.IdTokenVerifier, tokens, cookies.Nonce)
idToken, err := token.ParseIDToken(r.Context(), h.JwkSet, tokens)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
var claims struct {
SessionID string `json:"sid"`
validateOpts := []jwt.ValidateOption{
jwt.WithAudience(h.Config.ClientID),
jwt.WithClaimValue("nonce", cookies.Nonce),
jwt.WithIssuer(h.Config.WellKnown.Issuer),
}
if err := idToken.Claims(&claims); err != nil {
err = idToken.Validate(validateOpts...)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
err = h.setEncryptedCookie(w, SessionCookieName, claims.SessionID, SessionMaxLifetime)
err = h.setEncryptedCookie(w, SessionCookieName, idToken.SessionID, SessionMaxLifetime)
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
err = h.Sessions.Write(r.Context(), claims.SessionID, &session.Data{
ID: claims.SessionID,
err = h.Sessions.Write(r.Context(), idToken.SessionID, &session.Data{
ID: idToken.SessionID,
Token: tokens,
}, SessionMaxLifetime)
if err != nil {
@@ -287,7 +289,7 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
}
// Logout triggers self-initiated for the current user
// FrontChannelLogout triggers logout triggered by a third-party.
func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
@@ -307,25 +309,15 @@ func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
}
// From here on, check that 'iss' from request matches data found in access token.
tok, err := jwt.ParseSigned(sess.Token.AccessToken)
tok, err := jwt.Parse([]byte(sess.Token.AccessToken))
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var claims struct {
Issuer string `json:"iss"`
}
err = tok.UnsafeClaimsWithoutVerification(&claims)
err = jwt.Validate(tok, jwt.WithClaimValue("iss", iss))
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if claims.Issuer != iss {
w.WriteHeader(http.StatusBadRequest)
return
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"encoding/base64"
"fmt"
"github.com/nais/wonderwall/pkg/session"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
@@ -12,9 +11,11 @@ import (
"testing"
"time"
"golang.org/x/oauth2"
"github.com/lestrrat-go/jwx/jwk"
"github.com/coreos/go-oidc"
"github.com/nais/wonderwall/pkg/session"
"golang.org/x/oauth2"
"github.com/nais/wonderwall/pkg/cryptutil"
@@ -77,7 +78,6 @@ func handler() *router.Handler {
},
Crypter: cryptutil.New(encryptionKey),
UpstreamHost: "",
IdTokenVerifier: nil,
}
return &handler
}
@@ -147,11 +147,9 @@ func TestHandler_Callback_and_Logout(t *testing.T) {
h.Config.WellKnown.EndSessionEndpoint = idpserver.URL + "/endsession"
h.Config.RedirectURI = server.URL + "/oauth2/callback"
h.Config.PostLogoutRedirectURI = server.URL
h.IdTokenVerifier = oidc.NewVerifier(
cfg.WellKnown.Issuer,
oidc.NewRemoteKeySet(context.Background(), idpserver.URL+"/jwks"),
&oidc.Config{ClientID: cfg.ClientID},
)
jwkSet, err := jwk.Fetch(context.Background(), idpserver.URL+"/jwks")
assert.NoError(t, err)
h.JwkSet = jwkSet
jar, err := cookiejar.New(nil)
assert.NoError(t, err)
@@ -241,11 +239,10 @@ func TestHandler_FrontChannelLogout(t *testing.T) {
h.Config.WellKnown.EndSessionEndpoint = idpserver.URL + "/endsession"
h.Config.RedirectURI = server.URL + "/oauth2/callback"
h.Config.PostLogoutRedirectURI = server.URL
h.IdTokenVerifier = oidc.NewVerifier(
cfg.WellKnown.Issuer,
oidc.NewRemoteKeySet(context.Background(), idpserver.URL+"/jwks"),
&oidc.Config{ClientID: cfg.ClientID},
)
jwkSet, err := jwk.Fetch(context.Background(), idpserver.URL+"/jwks")
assert.NoError(t, err)
h.JwkSet = jwkSet
jar, err := cookiejar.New(nil)
assert.NoError(t, err)

View File

@@ -1,6 +1,17 @@
package token
const ScopeOpenID = "openid"
import (
"context"
"fmt"
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jwt"
"golang.org/x/oauth2"
"github.com/nais/wonderwall/pkg/keyset"
)
const ScopeOpenID = "openid"
type JWTTokenRequest struct {
Issuer string `json:"iss"`
@@ -10,3 +21,47 @@ type JWTTokenRequest struct {
IssuedAt int64 `json:"iat"`
ExpiresAt int64 `json:"exp"`
}
type IDToken struct {
Raw string
SessionID string
Token jwt.Token
}
func (in *IDToken) Validate(opts ...jwt.ValidateOption) error {
return jwt.Validate(in.Token, opts...)
}
func ParseIDToken(ctx context.Context, jwks jwk.Set, token *oauth2.Token) (*IDToken, error) {
raw, ok := token.Extra("id_token").(string)
if !ok {
return nil, fmt.Errorf("missing id_token in token response")
}
err := keyset.EnsureValid(ctx, jwks)
if err != nil {
return nil, err
}
parseOpts := []jwt.ParseOption{
jwt.WithKeySet(jwks),
jwt.WithRequiredClaim("sid"),
}
idToken, err := jwt.Parse([]byte(raw), parseOpts...)
if err != nil {
return nil, fmt.Errorf("parsing jwt: %w", err)
}
sessionID, ok := idToken.Get("sid")
if !ok {
return nil, fmt.Errorf("missing 'sid' claim in id_token")
}
result := &IDToken{
Raw: raw,
SessionID: sessionID.(string),
Token: idToken,
}
return result, nil
}