@@ -2,6 +2,9 @@ package oidc
22
33import (
44 "context"
5+ "encoding/json"
6+ "net"
7+ "net/http"
58 "os"
69 "path/filepath"
710 "time"
@@ -195,6 +198,21 @@ var _ = Describe("ProviderVerifier", func() {
195198 Expect(idToken.Subject).To(Equal(claims.Subject))
196199 },
197200 Entry("with the default opts and claims", &verifierTableInput{}),
201+ Entry("with skip discovery and an allowed signing algorithm", &verifierTableInput{
202+ modifyOpts: func(p *ProviderVerifierOptions) {
203+ p.SkipDiscovery = true
204+ p.JWKsURL = m.JWKSEndpoint()
205+ p.SupportedSigningAlgs = []string{"RS256"}
206+ },
207+ }),
208+ Entry("with skip discovery and a disallowed signing algorithm", &verifierTableInput{
209+ modifyOpts: func(p *ProviderVerifierOptions) {
210+ p.SkipDiscovery = true
211+ p.JWKsURL = m.JWKSEndpoint()
212+ p.SupportedSigningAlgs = []string{"HS256"}
213+ },
214+ expectedError: "failed to verify token: oidc: malformed jwt: unexpected signature algorithm \"RS256\"; expected [\"HS256\"]",
215+ }),
198216 Entry("when the audience is mismatched", &verifierTableInput{
199217 modifyClaims: func(j *jwt.RegisteredClaims) {
200218 j.Audience = jwt.ClaimStrings{"OtherClient"}
@@ -230,4 +248,78 @@ var _ = Describe("ProviderVerifier", func() {
230248 expectedError: "failed to verify token: oidc: token is expired",
231249 }),
232250 )
251+
252+ Describe("intersectSigningAlgs", func() {
253+ DescribeTable("when determining allowed signing algorithms", func(discoveredSigningAlgs, configuredSigningAlgs, expected []string, expectedError string) {
254+ actual, err := intersectSigningAlgs(discoveredSigningAlgs, configuredSigningAlgs)
255+ Expect(actual).To(Equal(expected))
256+ if len(expectedError) > 0 {
257+ Expect(err).To(HaveOccurred())
258+ Expect(err.Error()).To(Equal(expectedError))
259+ }
260+ },
261+ Entry("returns discovered values when no configured values are provided", []string{"RS256", "HS256"}, []string(nil), []string{"RS256", "HS256"}, ""),
262+ Entry("returns configured values when no discovered values are provided", []string(nil), []string{"RS256"}, []string{"RS256"}, ""),
263+ Entry("returns the configured order of the intersection", []string{"RS256", "HS256", "EdDSA"}, []string{"EdDSA", "RS256"}, []string{"EdDSA", "RS256"}, ""),
264+ Entry("returns an error when there is no intersection", []string{"RS256", "HS256"}, []string{"EdDSA"}, nil, "no supported signing algorithms in common between provider and configuration: discovered=[RS256 HS256], configured=[EdDSA]"),
265+ )
266+ })
267+
268+ It("uses the intersection between discovered and configured signing algorithms", func() {
269+ customServer, err := mockoidc.NewServer(nil)
270+ Expect(err).ToNot(HaveOccurred())
271+ customServer.AddMiddleware(newConfiguredSigningAlgsIssuerMiddleware(customServer, []string{"RS256", "HS256"}))
272+
273+ listener, err := net.Listen("tcp", "127.0.0.1:0")
274+ Expect(err).ToNot(HaveOccurred())
275+
276+ Expect(customServer.Start(listener, nil)).To(Succeed())
277+ defer func() {
278+ Expect(customServer.Shutdown()).To(Succeed())
279+ }()
280+
281+ pv, err := NewProviderVerifier(context.Background(), ProviderVerifierOptions{
282+ AudienceClaims: []string{"aud"},
283+ ClientID: customServer.Config().ClientID,
284+ ExtraAudiences: []string{},
285+ IssuerURL: customServer.Issuer(),
286+ SupportedSigningAlgs: []string{"HS256"},
287+ })
288+ Expect(err).ToNot(HaveOccurred())
289+
290+ rawIDToken, err := customServer.Keypair.SignJWT(jwt.RegisteredClaims{
291+ Audience: jwt.ClaimStrings{customServer.Config().ClientID},
292+ Issuer: customServer.Issuer(),
293+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Hour)),
294+ IssuedAt: jwt.NewNumericDate(time.Now()),
295+ Subject: "user",
296+ })
297+ Expect(err).ToNot(HaveOccurred())
298+
299+ _, err = pv.Verifier().Verify(context.Background(), rawIDToken)
300+ Expect(err).To(MatchError(HavePrefix("failed to verify token: oidc: malformed jwt: unexpected signature algorithm \"RS256\"; expected [\"HS256\"]")))
301+ })
233302})
303+
304+func newConfiguredSigningAlgsIssuerMiddleware(m *mockoidc.MockOIDC, supportedSigningAlgs []string) func(http.Handler) http.Handler {
305+ return func(next http.Handler) http.Handler {
306+ return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
307+ provider := providerJSON{
308+ Issuer: m.Issuer(),
309+ AuthURL: m.AuthorizationEndpoint(),
310+ TokenURL: m.TokenEndpoint(),
311+ JWKsURL: m.JWKSEndpoint(),
312+ UserInfoURL: m.UserinfoEndpoint(),
313+ SupportedSigningAlgs: supportedSigningAlgs,
314+ }
315+
316+ data, err := json.Marshal(provider)
317+ if err != nil {
318+ rw.WriteHeader(http.StatusInternalServerError)
319+ return
320+ }
321+
322+ _, _ = rw.Write(data)
323+ })
324+ }
325+}