put auth flag to jwt, dbl check in auth
This commit is contained in:
@@ -244,6 +244,8 @@ func makeAuthProviders(jwtService *auth.JWT, avatarProxy *proxy.Avatar, opts Opt
|
||||
RemarkURL: opts.RemarkURL,
|
||||
Cid: cid,
|
||||
Csecret: secret,
|
||||
Admins: opts.Admins,
|
||||
SecretKey: opts.SecretKey,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -439,13 +439,14 @@ func (s *Rest) configCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
LowScore: s.ScoreThresholds.Low,
|
||||
CriticalScore: s.ScoreThresholds.Critical,
|
||||
}
|
||||
authNames := []string{}
|
||||
|
||||
cnf.Auth = []string{}
|
||||
for _, ap := range s.Authenticator.Providers {
|
||||
authNames = append(authNames, ap.Name)
|
||||
cnf.Auth = append(cnf.Auth, ap.Name)
|
||||
}
|
||||
cnf.Auth = authNames
|
||||
if s.Authenticator.Admins == nil { // prevent json serialization to nil
|
||||
s.Authenticator.Admins = []string{}
|
||||
|
||||
if cnf.Admins == nil { // prevent json serialization to nil
|
||||
cnf.Admins = []string{}
|
||||
}
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, cnf)
|
||||
|
||||
+11
-7
@@ -14,8 +14,8 @@ import (
|
||||
// Authenticator is top level auth object providing middlewares
|
||||
type Authenticator struct {
|
||||
JWTService *JWT
|
||||
Admins []string
|
||||
Providers []Provider
|
||||
Admins []string
|
||||
DevPasswd string
|
||||
}
|
||||
|
||||
@@ -58,12 +58,7 @@ func (a *Authenticator) Auth(reqAuth bool) func(http.Handler) http.Handler {
|
||||
|
||||
if claims.User != nil { // if uinfo in token populate it to context
|
||||
user := *claims.User
|
||||
for _, admin := range a.Admins {
|
||||
if admin == user.ID {
|
||||
user.Admin = true
|
||||
break
|
||||
}
|
||||
}
|
||||
user.Admin = isAdmin(user.ID, a.Admins) // dbl-check for admin to reset admin flag even if token has it
|
||||
// refresh token if it close to expiration
|
||||
if _, err := a.JWTService.Refresh(w, r); err != nil {
|
||||
log.Printf("[WARN] can't refresh jwt, %s", err)
|
||||
@@ -124,3 +119,12 @@ func (a *Authenticator) basicDevUser(w http.ResponseWriter, r *http.Request) boo
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isAdmin(userID string, admins []string) bool {
|
||||
for _, admin := range admins {
|
||||
if admin == userID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ type Params struct {
|
||||
RemarkURL string
|
||||
AvatarProxy *proxy.Avatar
|
||||
JwtService *JWT
|
||||
Secret string
|
||||
SecretKey string
|
||||
Admins []string
|
||||
Cid string
|
||||
Csecret string
|
||||
}
|
||||
@@ -53,7 +54,7 @@ func (u userData) value(key string) string {
|
||||
}
|
||||
|
||||
// newProvider makes auth for given provider
|
||||
func initProvider(p Params, provider Provider) Provider {
|
||||
func initProvider(p Params, provider *Provider) Provider {
|
||||
log.Printf("[INFO] create %s auth, id=%s, redir: %s", provider.Name, provider.Cid, provider.RedirectURL)
|
||||
provider.Params = p
|
||||
conf := oauth2.Config{
|
||||
@@ -65,11 +66,11 @@ func initProvider(p Params, provider Provider) Provider {
|
||||
}
|
||||
|
||||
provider.conf = &conf
|
||||
return provider
|
||||
return *provider
|
||||
}
|
||||
|
||||
// Routes returns auth routes for given provider
|
||||
func (p Provider) Routes() chi.Router {
|
||||
func (p *Provider) Routes() chi.Router {
|
||||
router := chi.NewRouter()
|
||||
router.Get("/login", p.loginHandler)
|
||||
router.Get("/callback", p.authHandler)
|
||||
@@ -78,7 +79,7 @@ func (p Provider) Routes() chi.Router {
|
||||
}
|
||||
|
||||
// loginHandler - GET /login?from=redirect-back-url
|
||||
func (p Provider) loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func (p *Provider) loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// make state (random) and store in session
|
||||
state := p.randToken()
|
||||
@@ -108,7 +109,7 @@ func (p Provider) loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// authHandler fills user info and redirects to "from" url. This is callback url redirected locally by browser
|
||||
// GET /callback
|
||||
func (p Provider) authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func (p *Provider) authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
oauthClaims, err := p.JwtService.Get(r)
|
||||
if err != nil {
|
||||
@@ -163,6 +164,7 @@ func (p Provider) authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[WARN] failed to proxy avatar, %s", e)
|
||||
}
|
||||
}
|
||||
u.Admin = isAdmin(u.ID, p.Admins)
|
||||
|
||||
authClaims := &CustomClaims{
|
||||
User: &u,
|
||||
@@ -184,16 +186,16 @@ func (p Provider) authHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, oauthClaims.From, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
render.JSON(w, r, jData)
|
||||
render.JSON(w, r, &u)
|
||||
}
|
||||
|
||||
// LogoutHandler - GET /logout
|
||||
func (p Provider) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func (p *Provider) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
p.JwtService.Reset(w)
|
||||
log.Printf("[DEBUG] logout")
|
||||
}
|
||||
|
||||
func (p Provider) randToken() string {
|
||||
func (p *Provider) randToken() string {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
log.Fatalf("[ERROR] can't get randoms, %s", err)
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
|
||||
_, ts, ots := mockProvider(t, 8981, 8982)
|
||||
p, ts, ots := mockProvider(t, 8981, 8982)
|
||||
defer func() {
|
||||
ts.Close()
|
||||
ots.Close()
|
||||
@@ -46,8 +46,20 @@ func TestLogin(t *testing.T) {
|
||||
u := store.User{}
|
||||
err = json.Unmarshal(body, &u)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, store.User{Name: "blah", ID: "myuser", Picture: "",
|
||||
assert.Equal(t, store.User{Name: "blah", ID: "mock_myuser", Picture: "http://exmple.com/pic1.png",
|
||||
Admin: false, Blocked: false, IP: ""}, u)
|
||||
|
||||
// check admin user
|
||||
p.Admins = []string{"mock_myuser"}
|
||||
resp, err = client.Get("http://localhost:8981/login")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
assert.Nil(t, err)
|
||||
err = json.Unmarshal(body, &u)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, store.User{Name: "blah", ID: "mock_myuser", Picture: "http://exmple.com/pic1.png",
|
||||
Admin: true, Blocked: false, IP: ""}, u)
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
@@ -78,19 +90,19 @@ func TestLogout(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInitProvider(t *testing.T) {
|
||||
params := Params{RemarkURL: "url", Secret: "123456", Cid: "cid", Csecret: "csecret"}
|
||||
params := Params{RemarkURL: "url", SecretKey: "123456", Cid: "cid", Csecret: "csecret"}
|
||||
provider := Provider{Name: "test", RedirectURL: "redir"}
|
||||
res := initProvider(params, provider)
|
||||
res := initProvider(params, &provider)
|
||||
assert.Equal(t, "cid", res.conf.ClientID)
|
||||
assert.Equal(t, "csecret", res.conf.ClientSecret)
|
||||
assert.Equal(t, "redir", res.RedirectURL)
|
||||
assert.Equal(t, "123456", res.Secret)
|
||||
assert.Equal(t, "123456", res.SecretKey)
|
||||
assert.Equal(t, "test", res.Name)
|
||||
}
|
||||
|
||||
func mockProvider(t *testing.T, loginPort, authPort int) (provider Provider, ts *http.Server, oauth *http.Server) {
|
||||
func mockProvider(t *testing.T, loginPort, authPort int) (provider *Provider, ts *http.Server, oauth *http.Server) {
|
||||
|
||||
provider = Provider{
|
||||
provider = &Provider{
|
||||
Name: "mock",
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("http://localhost:%d/login/oauth/authorize", authPort),
|
||||
@@ -101,15 +113,16 @@ func mockProvider(t *testing.T, loginPort, authPort int) (provider Provider, ts
|
||||
InfoURL: fmt.Sprintf("http://localhost:%d/user", authPort),
|
||||
MapUser: func(data userData, _ []byte) store.User {
|
||||
userInfo := store.User{
|
||||
ID: data.value("id"),
|
||||
ID: "mock_" + data.value("id"),
|
||||
Name: data.value("name"),
|
||||
Picture: data.value("picture"),
|
||||
}
|
||||
return userInfo
|
||||
},
|
||||
}
|
||||
jwtServcie := NewJWT("12345", false, time.Hour)
|
||||
provider = initProvider(Params{RemarkURL: "url", Secret: "123456", Cid: "cid", Csecret: "csecret", JwtService: jwtServcie}, provider)
|
||||
params := Params{RemarkURL: "url", SecretKey: "123456", Cid: "cid", Csecret: "csecret",
|
||||
JwtService: NewJWT("12345", false, time.Hour), Admins: []string{""}}
|
||||
initProvider(params, provider)
|
||||
|
||||
ts = &http.Server{Addr: fmt.Sprintf(":%d", loginPort), Handler: provider.Routes()}
|
||||
|
||||
@@ -138,7 +151,7 @@ func mockProvider(t *testing.T, loginPort, authPort int) (provider Provider, ts
|
||||
res := `{
|
||||
"id":"myuser",
|
||||
"name":"blah",
|
||||
"profile": "http://blah.com/p.html"
|
||||
"picture":"http://exmple.com/pic1.png"
|
||||
}`
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(200)
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
// NewGoogle makes google oauth2 provider
|
||||
func NewGoogle(p Params) Provider {
|
||||
return initProvider(p, Provider{
|
||||
return initProvider(p, &Provider{
|
||||
Name: "google",
|
||||
Endpoint: google.Endpoint,
|
||||
RedirectURL: p.RemarkURL + "/auth/google/callback",
|
||||
@@ -37,7 +37,7 @@ func NewGoogle(p Params) Provider {
|
||||
|
||||
// NewGithub makes github oauth2 provider
|
||||
func NewGithub(p Params) Provider {
|
||||
return initProvider(p, Provider{
|
||||
return initProvider(p, &Provider{
|
||||
Name: "github",
|
||||
Endpoint: github.Endpoint,
|
||||
RedirectURL: p.RemarkURL + "/auth/github/callback",
|
||||
@@ -75,7 +75,7 @@ func NewFacebook(p Params) Provider {
|
||||
} `json:"picture"`
|
||||
}
|
||||
|
||||
return initProvider(p, Provider{
|
||||
return initProvider(p, &Provider{
|
||||
Name: "facebook",
|
||||
Endpoint: facebook.Endpoint,
|
||||
RedirectURL: p.RemarkURL + "/auth/facebook/callback",
|
||||
@@ -101,7 +101,7 @@ func NewFacebook(p Params) Provider {
|
||||
|
||||
// NewDisqus makes disqus oauth2 provider. TODO: WIP - seems to need client_id param
|
||||
func NewDisqus(p Params) Provider {
|
||||
return initProvider(p, Provider{
|
||||
return initProvider(p, &Provider{
|
||||
Name: "disqus",
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://disqus.com/api/oauth/2.0/authorize/",
|
||||
|
||||
Reference in New Issue
Block a user