auth test
This commit is contained in:
@@ -77,7 +77,7 @@ func (p Provider) Routes() chi.Router {
|
||||
return router
|
||||
}
|
||||
|
||||
// LoginHandler - GET /login/{provider}?from=redirect-back-url
|
||||
// LoginHandler - GET /login?from=redirect-back-url
|
||||
func (p Provider) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// make state (random) and store in session
|
||||
@@ -106,6 +106,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) {
|
||||
|
||||
session, err := p.Get(r, "remark")
|
||||
@@ -116,8 +117,13 @@ func (p Provider) AuthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// compare saved state to the one from redirect url
|
||||
retrievedState, ok := session.Values["state"]
|
||||
if !ok || retrievedState != r.URL.Query().Get("state") {
|
||||
http.Error(w, fmt.Sprintf("unexpected state %s", retrievedState.(string)), http.StatusUnauthorized)
|
||||
if !ok {
|
||||
http.Error(w, "missing state in store", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if retrievedState == "" || retrievedState != r.URL.Query().Get("state") {
|
||||
http.Error(w, fmt.Sprintf("unexpected state %v", retrievedState), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/umputun/remark/app/store"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
|
||||
sessionStore := &mockStore{values: make(map[interface{}]interface{})}
|
||||
|
||||
_, ts, ots := mockProvider(t, sessionStore)
|
||||
defer func() {
|
||||
ts.Close()
|
||||
ots.Close()
|
||||
}()
|
||||
|
||||
resp, err := http.Get("http://localhost:8081/login")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
t.Logf("resp %s", string(body))
|
||||
u := store.User{}
|
||||
err = json.Unmarshal(body, &u)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, store.User{Name: "blah", ID: "myuser", Picture: "", Profile: "", Admin: false, Blocked: false, IP: ""}, u)
|
||||
|
||||
}
|
||||
|
||||
func mockProvider(t *testing.T, sessStore sessions.Store) (provder Provider, ts *http.Server, oauth *http.Server) {
|
||||
|
||||
provider := Provider{
|
||||
Name: "mock",
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "http://localhost:8082/login/oauth/authorize",
|
||||
TokenURL: "http://localhost:8082/login/oauth/access_token",
|
||||
},
|
||||
RedirectURL: "http://localhost:8081/callback",
|
||||
Scopes: []string{"user:email"},
|
||||
InfoURL: "http://localhost:8082/user",
|
||||
MapUser: func(data userData) store.User {
|
||||
userInfo := store.User{
|
||||
ID: data.value("id"),
|
||||
Name: data.value("name"),
|
||||
Picture: data.value("pictrue"),
|
||||
Profile: data.value("profile"),
|
||||
}
|
||||
return userInfo
|
||||
},
|
||||
}
|
||||
|
||||
provder = initProvider(Params{SessionStore: sessStore, Cid: "cid", Csecret: "csecret"}, provider)
|
||||
|
||||
ts = &http.Server{Addr: ":8081", Handler: provder.Routes()}
|
||||
|
||||
oauth = &http.Server{
|
||||
Addr: ":8082",
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[MOCK OAUTH] request %s %s %+v", r.Method, r.URL, r.Header)
|
||||
switch {
|
||||
case strings.HasPrefix(r.URL.Path, "/login/oauth/authorize"):
|
||||
state := r.URL.Query().Get("state")
|
||||
w.Header().Add("Location", "http://localhost:8081/callback?code=g0ZGZmNjVmOWI&state="+state)
|
||||
w.WriteHeader(302)
|
||||
case strings.HasPrefix(r.URL.Path, "/login/oauth/access_token"):
|
||||
res := `{
|
||||
"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
|
||||
"token_type":"bearer",
|
||||
"expires_in":3600,
|
||||
"refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
|
||||
"scope":"create",
|
||||
"state":"12345678"
|
||||
}`
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte(res))
|
||||
case strings.HasPrefix(r.URL.Path, "/user"):
|
||||
res := `{
|
||||
"id":"myuser",
|
||||
"name":"blah"
|
||||
}`
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte(res))
|
||||
default:
|
||||
t.Logf("unexpected oauth request %s %s", r.Method, r.URL)
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
go oauth.ListenAndServe()
|
||||
go ts.ListenAndServe()
|
||||
|
||||
return provider, ts, oauth
|
||||
}
|
||||
|
||||
type mockStore struct {
|
||||
values map[interface{}]interface{}
|
||||
}
|
||||
|
||||
func (ms *mockStore) Get(r *http.Request, name string) (*sessions.Session, error) {
|
||||
if ms.values == nil {
|
||||
ms.values = make(map[interface{}]interface{})
|
||||
}
|
||||
s := sessions.NewSession(ms, name)
|
||||
s.Values = ms.values
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (ms *mockStore) New(r *http.Request, name string) (*sessions.Session, error) {
|
||||
ms.values = make(map[interface{}]interface{})
|
||||
return &sessions.Session{Values: ms.values}, nil
|
||||
}
|
||||
|
||||
func (ms *mockStore) Save(r *http.Request, w http.ResponseWriter, s *sessions.Session) error {
|
||||
if ms.values == nil {
|
||||
ms.values = make(map[interface{}]interface{})
|
||||
}
|
||||
ms.values = s.Values
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user