-
-
Notifications
You must be signed in to change notification settings - Fork 280
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
Added support for JWT generated by IDPs like Keycloak #871
Changes from 3 commits
c801f55
0cc0bd4
7b33dbd
fee30e7
03330b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
package config | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/lestrrat-go/jwx/v2/jwk" | ||
"github.com/prest/prest/adapters" | ||
"github.com/prest/prest/cache" | ||
|
||
"net/http" | ||
|
||
homedir "github.com/mitchellh/go-homedir" | ||
"github.com/spf13/viper" | ||
"github.com/structy/log" | ||
|
@@ -82,6 +88,8 @@ type Prest struct { | |
PGCache bool | ||
JWTKey string | ||
JWTAlgo string | ||
JWTWellKnown string | ||
JWTJWKS string | ||
JWTWhiteList []string | ||
JSONAggType string | ||
MigrationsPath string | ||
|
@@ -171,6 +179,8 @@ func viperCfg() { | |
|
||
viper.SetDefault("jwt.default", true) | ||
viper.SetDefault("jwt.algo", "HS256") | ||
viper.SetDefault("jwt.wellknown", "") | ||
viper.SetDefault("jwt.jwks", "") | ||
viper.SetDefault("jwt.whitelist", []string{"/auth"}) | ||
|
||
viper.SetDefault("json.agg.type", "jsonb_agg") | ||
|
@@ -271,7 +281,10 @@ func Parse(cfg *Prest) { | |
cfg.SingleDB = viper.GetBool("pg.single") | ||
cfg.JWTKey = viper.GetString("jwt.key") | ||
cfg.JWTAlgo = viper.GetString("jwt.algo") | ||
cfg.JWTWellKnown = viper.GetString("jwt.wellknown") | ||
cfg.JWTJWKS = viper.GetString("jwt.jwks") | ||
cfg.JWTWhiteList = viper.GetStringSlice("jwt.whitelist") | ||
fetchJWKS(cfg) | ||
|
||
cfg.JSONAggType = getJSONAgg() | ||
|
||
|
@@ -358,6 +371,50 @@ func parseDatabaseURL(cfg *Prest) { | |
} | ||
} | ||
|
||
// fetchJWKS tries to get the JWKS from the URL in the config | ||
func fetchJWKS(cfg *Prest) { | ||
if cfg.JWTWellKnown == "" { | ||
log.Debugln("no JWT WellKnown url found, skipping") | ||
return | ||
} | ||
if cfg.JWTJWKS != "" { | ||
log.Debugln("JWKS already set, skipping") | ||
return | ||
} | ||
|
||
// Call provider to obtain .well-known config | ||
r, err := http.Get(cfg.JWTWellKnown) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add context to this call with a 5s timeout There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in latest commit. |
||
if err != nil { | ||
log.Errorf("Cannot get .well-known configuration from '%s'. err: %v\n", cfg.JWTWellKnown, err) | ||
return | ||
} | ||
defer r.Body.Close() | ||
|
||
var wellKnown map[string]interface{} | ||
err = json.NewDecoder(r.Body).Decode(&wellKnown) | ||
if err != nil { | ||
log.Errorf("Failed to decode JSON: %v\n", err) | ||
return | ||
} | ||
|
||
//Retrieve the JWKS from the endpoint | ||
JWKSet, err := jwk.Fetch(context.Background(), wellKnown["jwks_uri"].(string)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you split this conversion into a variable? just to make sure that it never panics: uri, ok := wellKnown["jwks_uri"].(string)
...
JWKSet, err := jwk.Fetch(context.Background(),uri) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in latest commit. |
||
if err != nil { | ||
err := fmt.Errorf("failed to parse JWK: %s", err) | ||
log.Errorf("Failed to fetch JWK: %v\n", err) | ||
return | ||
} | ||
|
||
//Convert set to json string | ||
jwkSetJSON, err := json.Marshal(JWKSet) | ||
if err != nil { | ||
log.Errorf("Failed to marshal JWKSet to JSON: %v\n", err) | ||
return | ||
} | ||
|
||
cfg.JWTJWKS = string(jwkSetJSON) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Refactor the |
||
|
||
func portFromEnv(cfg *Prest) { | ||
if os.Getenv("PORT") == "" { | ||
log.Debugln("could not find PORT in env") | ||
|
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you rename this to
JWTWellKnownURL
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in latest commit.
fee30e7