loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

commit 72f342f3f4a3468579ccf0aee996db5925bad2e1
parent be2ae2ce04f3f9e5287e78121636134cc49b2fa2
Author: Jakob Rockenbauch <34475067+J-Rocke@users.noreply.github.com>
Date:   Fri,  6 Dec 2019 14:11:28 +0100

Merge pull request #156 from g-w/crypto-rand

Use crypto/rand
Diffstat:
Mlogin/config.go | 21++++++++++++---------
Moauth2/manager.go | 5+++--
Moauth2/manager_test.go | 11+++++++----
Moauth2/oauth.go | 28+++++++++++++++-------------
4 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/login/config.go b/login/config.go @@ -1,11 +1,12 @@ package login import ( + "crypto/rand" + "encoding/hex" "errors" "flag" "fmt" "io/ioutil" - "math/rand" "os" "strings" "time" @@ -17,8 +18,11 @@ import ( var jwtDefaultSecret string func init() { - rand.Seed(time.Now().UTC().UnixNano()) - jwtDefaultSecret = randStringBytes(32) + var err error + jwtDefaultSecret, err = randStringBytes(64) + if err != nil { + panic(err) + } } // DefaultConfig for the loginsrv handler @@ -231,14 +235,13 @@ func readConfig(f *flag.FlagSet, args []string) (*Config, error) { return config, err } -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -func randStringBytes(n int) string { +func randStringBytes(n int) (string, error) { b := make([]byte, n) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] + _, err := rand.Read(b) + if err != nil { + return "", err } - return string(b) + return hex.EncodeToString(b), nil } func envName(flagName string) string { diff --git a/oauth2/manager.go b/oauth2/manager.go @@ -2,17 +2,18 @@ package oauth2 import ( "fmt" - "github.com/tarent/loginsrv/model" "net/http" "net/url" "strings" + + "github.com/tarent/loginsrv/model" ) // Manager has the responsibility to handle the user user requests in an oauth flow. // It has to pick the right configuration and start the oauth redirecting. type Manager struct { configs map[string]Config - startFlow func(cfg Config, w http.ResponseWriter) + startFlow func(cfg Config, w http.ResponseWriter) error authenticate func(cfg Config, r *http.Request) (TokenInfo, error) } diff --git a/oauth2/manager_test.go b/oauth2/manager_test.go @@ -3,11 +3,12 @@ package oauth2 import ( "crypto/tls" "errors" - . "github.com/stretchr/testify/assert" - "github.com/tarent/loginsrv/model" "net/http" "net/http/httptest" "testing" + + . "github.com/stretchr/testify/assert" + "github.com/tarent/loginsrv/model" ) func Test_Manager_Positive_Flow(t *testing.T) { @@ -48,9 +49,10 @@ func Test_Manager_Positive_Flow(t *testing.T) { "redirect_uri": expectedConfig.RedirectURI, }) - m.startFlow = func(cfg Config, w http.ResponseWriter) { + m.startFlow = func(cfg Config, w http.ResponseWriter) error { startFlowCalled = true startFlowReceivedConfig = cfg + return nil } m.authenticate = func(cfg Config, r *http.Request) (TokenInfo, error) { @@ -233,8 +235,9 @@ func Test_Manager_RedirectURI_Generation(t *testing.T) { "scope": "bazz", }) - m.startFlow = func(cfg Config, w http.ResponseWriter) { + m.startFlow = func(cfg Config, w http.ResponseWriter) error { startFlowReceivedConfig = cfg + return nil } callURL := "http://example.com/login/github" diff --git a/oauth2/oauth.go b/oauth2/oauth.go @@ -2,20 +2,17 @@ package oauth2 import ( "context" + "crypto/rand" + "encoding/hex" "encoding/json" "fmt" "io/ioutil" - "math/rand" "net/http" "net/url" "strings" "time" ) -func init() { - rand.Seed(time.Now().UTC().UnixNano()) -} - // Config describes a typical 3-legged OAuth2 flow, with both the // client application information and the server's endpoint URLs. type Config struct { @@ -67,7 +64,7 @@ const defaultTimeout = 5 * time.Second // StartFlow by redirecting the user to the login provider. // A state parameter to protect against cross-site request forgery attacks is randomly generated and stored in a cookie -func StartFlow(cfg Config, w http.ResponseWriter) { +func StartFlow(cfg Config, w http.ResponseWriter) error { values := make(url.Values) values.Set("client_id", cfg.ClientID) values.Set("scope", cfg.Scope) @@ -75,7 +72,11 @@ func StartFlow(cfg Config, w http.ResponseWriter) { values.Set("response_type", "code") // set and store the state param - values.Set("state", randStringBytes(15)) + state, err := randStringBytes(32) + if err != nil { + return err + } + values.Set("state", state) http.SetCookie(w, &http.Cookie{ Name: stateCookieName, MaxAge: 60 * 10, // 10 minutes @@ -86,6 +87,8 @@ func StartFlow(cfg Config, w http.ResponseWriter) { targetURL := cfg.AuthURL + "?" + values.Encode() w.Header().Set("Location", targetURL) w.WriteHeader(http.StatusFound) + + return nil } // Authenticate after coming back from the oauth flow. @@ -154,12 +157,11 @@ func getAccessToken(cfg Config, state, code string) (TokenInfo, error) { return tokenInfo, nil } -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -func randStringBytes(n int) string { +func randStringBytes(n int) (string, error) { b := make([]byte, n) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] + _, err := rand.Read(b) + if err != nil { + return "", err } - return string(b) + return hex.EncodeToString(b), nil }