diff --git a/api/auth.go b/api/auth.go index d1b380a..dc383d2 100644 --- a/api/auth.go +++ b/api/auth.go @@ -2,6 +2,8 @@ package api import ( "context" + "crypto/rsa" + "io/ioutil" "net/http" jwt "github.com/dgrijalva/jwt-go" @@ -36,9 +38,21 @@ func (a *API) extractBearerToken(w http.ResponseWriter, r *http.Request) (string func (a *API) parseJWTClaims(bearer string, r *http.Request) (context.Context, error) { config := getConfig(r.Context()) - p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}} + p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name, jwt.SigningMethodRS256.Name}} token, err := p.ParseWithClaims(bearer, &GatewayClaims{}, func(token *jwt.Token) (interface{}, error) { - return []byte(config.JWT.Secret), nil + signMethod := config.JWT.Method + if signMethod == "" { + signMethod = "HS256" // don't break backwards compatibility + } + + switch signMethod { + case "HS256": + return []byte(config.JWT.Secret), nil + case "RS256": + return loadRSAPublicKeyFromDisk(config.JWT.Keyfile), nil + default: + return nil, unauthorizedError("Invalid Signing Method: %s", signMethod) + } }) if err != nil { return nil, unauthorizedError("Invalid token: %v", err) @@ -46,3 +60,15 @@ func (a *API) parseJWTClaims(bearer string, r *http.Request) (context.Context, e return withToken(r.Context(), token), nil } + +func loadRSAPublicKeyFromDisk(location string) *rsa.PublicKey { + keyData, e := ioutil.ReadFile(location) + if e != nil { + panic(e.Error()) + } + key, e := jwt.ParseRSAPublicKeyFromPEM(keyData) + if e != nil { + panic(e.Error()) + } + return key +} diff --git a/conf/configuration.go b/conf/configuration.go index d162f8a..7290dab 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -45,7 +45,9 @@ type DBConfiguration struct { // JWTConfiguration holds all the JWT related configuration. type JWTConfiguration struct { - Secret string `json:"secret" required:"true"` + Method string `envconfig:"SIGNING_METHOD" json:"method"` + Secret string `envconfig:"SECRET" json:"secret"` + Keyfile string `envconfig:"KEYFILE" json:"keyfile"` } // GlobalConfiguration holds all the configuration that applies to all instances. diff --git a/example.env b/example.env index 2d6691f..81c6fb7 100644 --- a/example.env +++ b/example.env @@ -1,4 +1,6 @@ -GITGATEWAY_JWT_SECRET="CHANGE-THIS! VERY IMPORTANT!" +GITGATEWAY_JWT_SIGNING_METHOD="HS256" # [HS256|RS256] +GITGATEWAY_JWT_SECRET="CHANGE-THIS! VERY IMPORTANT!" # HS256 +#GITGATEWAY_JWT_KEYFILE="/path/to/keyfile.pub" # RS256 GITGATEWAY_DB_DRIVER=sqlite3 DATABASE_URL=gorm.db