1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-24 05:17:10 +02:00
authboss/recover/complete_test.go
2015-02-15 21:39:18 -08:00

371 lines
10 KiB
Go

package recover
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"testing"
"time"
"golang.org/x/crypto/bcrypt"
"gopkg.in/authboss.v0"
"gopkg.in/authboss.v0/internal/mocks"
)
const (
testUrlBase64Token = "MTIzNA=="
testStdBase64Token = "gdyb21LQTcIANtvYMT7QVQ=="
)
func Test_recoverCompleteHandlerFunc_GET_TokenExpired(t *testing.T) {
m, logger := testValidRecoverModule()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["b"] = authboss.Attributes{
attrUsername: "b",
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(-24) * time.Hour),
}
w, r, ctx := testHttpRequest("GET", fmt.Sprintf("/recover/complete?token=%s", testUrlBase64Token), nil)
clientStorer := mocks.NewMockClientStorer()
ctx.SessionStorer = clientStorer
m.recoverCompleteHandlerFunc(ctx, w, r)
actualLog, err := ioutil.ReadAll(logger)
if err != nil {
panic(err)
}
if !bytes.Contains(actualLog, []byte("recover [token expired]:")) {
t.Error("Expected logs to start with:", "recover [token expired]:")
}
if flash := clientStorer.Values[authboss.FlashErrorKey]; flash != authboss.Cfg.RecoverTokenExpiredFlash {
t.Error("Unexpected error flash:", flash)
}
if location := w.Header().Get("Location"); location != "/recover" {
t.Error("Unexpected location:", location)
}
}
func Test_recoverCompleteHandlerFunc_GET_OtherErrors(t *testing.T) {
m, logger := testValidRecoverModule()
w, r, ctx := testHttpRequest("GET", "/recover/complete?token=asdf", nil)
m.recoverCompleteHandlerFunc(ctx, w, r)
actualLog, err := ioutil.ReadAll(logger)
if err != nil {
panic(err)
}
if !bytes.Contains(actualLog, []byte("recover:")) {
t.Error("Expected logs to start with:", "recover:")
}
if location := w.Header().Get("Location"); location != "/" {
t.Error("Unexpected location:", location)
}
}
func Test_recoverCompleteHandlerFunc_GET(t *testing.T) {
m, _ := testValidRecoverModule()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["b"] = authboss.Attributes{
attrUsername: "b",
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
}
w, r, ctx := testHttpRequest("GET", fmt.Sprintf("/recover/complete?token=%s", testUrlBase64Token), nil)
sessionStorer := mocks.NewMockClientStorer()
sessionStorer.Values = map[string]string{authboss.FlashErrorKey: "asdf"}
ctx.SessionStorer = sessionStorer
m.recoverCompleteHandlerFunc(ctx, w, r)
page := pageRecoverComplete{
Token: testUrlBase64Token,
FlashError: "asdf",
XSRFName: authboss.Cfg.XSRFName,
XSRFToken: authboss.Cfg.XSRFMaker(nil, nil),
}
expectedBody := &bytes.Buffer{}
if err := m.templates[tplRecoverComplete].Execute(expectedBody, page); err != nil {
panic(err)
}
if w.Code != http.StatusOK {
t.Error("Unexpected code:", w.Code)
}
if !bytes.Equal(expectedBody.Bytes(), w.Body.Bytes()) {
t.Error("Unexpected body:", w.Body.String())
}
}
func Test_recoverCompleteHandlerFunc_POST_RecoveryCompleteFailed(t *testing.T) {
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest(
"POST",
fmt.Sprintf("/recover/complete?token=%s", testUrlBase64Token),
url.Values{"password": []string{"a"}, "confirmPassword": []string{"a"}},
)
tpl := m.templates[tplRecoverComplete]
expectedBody := &bytes.Buffer{}
if err := tpl.Execute(expectedBody, pageRecoverComplete{
Token: testUrlBase64Token,
Password: "a",
ConfirmPassword: "a",
FlashError: authboss.Cfg.RecoverFailedErrorFlash,
XSRFName: authboss.Cfg.XSRFName,
XSRFToken: authboss.Cfg.XSRFMaker(nil, nil),
}); err != nil {
panic(err)
}
// missing storer will cause this to fail
m.recoverCompleteHandlerFunc(ctx, w, r)
if w.Code != http.StatusOK {
t.Error("Unexpected code:", w.Code)
}
if !bytes.Equal(expectedBody.Bytes(), w.Body.Bytes()) {
t.Error("Unexpected body:", w.Body.String())
}
}
func Test_recoverCompleteHandlerFunc_POST(t *testing.T) {
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest(
"POST",
fmt.Sprintf("/recover/complete?token=%s", testUrlBase64Token),
url.Values{"password": []string{"a"}, "confirmPassword": []string{"a"}},
)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["a"] = authboss.Attributes{
attrUsername: "a",
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
}
m.recoverCompleteHandlerFunc(ctx, w, r)
if w.Code != http.StatusFound {
t.Error("Unexpected code:", w.Code)
}
location := w.Header().Get("Location")
if location != "/login" {
t.Error("Unexpected redirect:", location)
}
}
func Test_verifyToken_MissingToken(t *testing.T) {
authboss.NewConfig()
ctx := mocks.MockRequestContext()
_, err := verifyToken(ctx, nil)
if err.Error() != "missing form value: token" {
t.Error("Unexpected error:", err)
}
}
func Test_verifyToken_InvalidToken(t *testing.T) {
authboss.NewConfig()
testValidTestConfig()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["a"] = authboss.Attributes{
attrRecoverToken: testStdBase64Token,
}
ctx := mocks.MockRequestContext("token", "asdf")
_, err := verifyToken(ctx, storer)
if err.Error() != authboss.ErrUserNotFound.Error() {
t.Error("Unexpected error:", err)
}
}
func Test_verifyToken_ExpiredToken(t *testing.T) {
testValidTestConfig()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["a"] = authboss.Attributes{
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(-24) * time.Hour),
}
ctx := mocks.MockRequestContext("token", testUrlBase64Token)
_, err := verifyToken(ctx, storer)
if err.Error() != "recovery token expired" {
t.Error("Unexpected error:", err)
}
}
func Test_verifyToken(t *testing.T) {
testValidTestConfig()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["a"] = authboss.Attributes{
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
}
ctx := mocks.MockRequestContext("token", testUrlBase64Token)
attrs, err := verifyToken(ctx, storer)
if err != nil {
t.Error("Unexpected error:", err)
}
if attrs == nil {
t.Error("Unexpected nil attrs")
}
}
func Test_recoverComplete_TokenVerificationFails(t *testing.T) {
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext()
errPage := m.recoverComplete(ctx, "", "")
if errPage == nil {
t.Error("Expected err page")
}
if !reflect.DeepEqual(*errPage, pageRecoverComplete{FlashError: authboss.Cfg.RecoverFailedErrorFlash}) {
t.Error("Unexpected err page:", errPage)
}
actualLog, err := ioutil.ReadAll(logger)
if err != nil {
panic(err)
}
if !bytes.Contains(actualLog, []byte("recover [failed to verify token]:")) {
t.Error("Expected logs to start with:", "recover [failed to verify token]:")
}
}
func Test_recoverComplete_ValidationFails(t *testing.T) {
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext("token", testUrlBase64Token, "password", "a", "confirmPassword", "b")
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["b"] = authboss.Attributes{
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
}
errPage := m.recoverComplete(ctx, "", "")
if errPage == nil {
t.Error("Expected err page")
}
expectedErrPage := pageRecoverComplete{
Token: testUrlBase64Token,
Password: "a",
ConfirmPassword: "b",
ErrMap: map[string][]string{"confirmPassword": []string{"Does not match password"}},
}
if !reflect.DeepEqual(*errPage, expectedErrPage) {
t.Error("Unexpected err page:", errPage)
}
actualLog, err := ioutil.ReadAll(logger)
if err != nil {
panic(err)
}
expetedLog := []byte("recover [validation failed]: confirmPassword: Does not match password\n")
if !bytes.Equal(actualLog, expetedLog) {
t.Error("Expected logs:", string(expetedLog))
}
}
func Test_recoverComplete(t *testing.T) {
m, _ := testValidRecoverModule()
ctx := mocks.MockRequestContext("token", testUrlBase64Token, "password", "a", "confirmPassword", "a")
clientStorer := mocks.NewMockClientStorer()
ctx.SessionStorer = clientStorer
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
storer.Users["b"] = authboss.Attributes{
attrUsername: "b",
attrRecoverToken: testStdBase64Token,
attrRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
}
if errPage := m.recoverComplete(ctx, "", ""); errPage != nil {
t.Error("Expected nil err page")
}
password, ok := storer.Users["b"].String(attrPassword)
if !ok {
panic("cannot find password")
}
if err := bcrypt.CompareHashAndPassword([]byte(password), []byte("a")); err != nil {
t.Error("Unexpected encrypted password")
}
recoverToken, ok := storer.Users["b"].String(attrRecoverToken)
if !ok {
panic("cannot find token")
}
if recoverToken != "" {
t.Error("Unexpected recover token:", recoverToken)
}
recoverTokenExpiry, ok := storer.Users["b"].DateTime(attrRecoverTokenExpiry)
if !ok {
panic("cannot find token")
}
var nullTime time.Time
if recoverTokenExpiry != nullTime {
t.Error("Unexpected recover token expiry:", recoverTokenExpiry)
}
}
func Test_recoverCompleteHandlerFunc_OtherMethods(t *testing.T) {
m, _ := testValidRecoverModule()
for i, method := range []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"} {
w, r, _ := testHttpRequest(method, "/recover/complete", nil)
m.recoverHandlerFunc(nil, w, r)
if http.StatusMethodNotAllowed != w.Code {
t.Errorf("%d> Expected status code %d, got %d", i, http.StatusMethodNotAllowed, w.Code)
continue
}
}
}