2020-07-28 15:23:17 +01:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package consoleapi_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2021-11-18 18:55:37 +00:00
|
|
|
"context"
|
2020-07-28 15:23:17 +01:00
|
|
|
"encoding/json"
|
2021-05-14 16:05:42 +01:00
|
|
|
"errors"
|
2020-10-21 11:52:24 +01:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"math/rand"
|
2020-07-28 15:23:17 +01:00
|
|
|
"net/http"
|
2020-10-21 11:52:24 +01:00
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"reflect"
|
2020-07-28 15:23:17 +01:00
|
|
|
"strconv"
|
2020-10-21 11:52:24 +01:00
|
|
|
"strings"
|
2020-07-28 15:23:17 +01:00
|
|
|
"testing"
|
2020-10-21 11:52:24 +01:00
|
|
|
"testing/quick"
|
2021-07-13 18:21:16 +01:00
|
|
|
"time"
|
2020-07-28 15:23:17 +01:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
|
"storj.io/common/testcontext"
|
2022-08-01 12:43:23 +01:00
|
|
|
"storj.io/common/testrand"
|
2021-11-18 18:55:37 +00:00
|
|
|
"storj.io/storj/private/post"
|
2020-07-28 15:23:17 +01:00
|
|
|
"storj.io/storj/private/testplanet"
|
|
|
|
"storj.io/storj/satellite"
|
2021-07-13 18:21:16 +01:00
|
|
|
"storj.io/storj/satellite/console"
|
2020-10-21 11:52:24 +01:00
|
|
|
"storj.io/storj/satellite/console/consoleweb/consoleapi"
|
2020-07-28 15:23:17 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestAuth_Register(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
|
|
|
config.Console.OpenRegistrationEnabled = true
|
|
|
|
config.Console.RateLimit.Burst = 10
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
config.Mail.AuthType = "nomail"
|
2020-07-28 15:23:17 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
for i, test := range []struct {
|
|
|
|
Partner string
|
|
|
|
ValidPartner bool
|
|
|
|
}{
|
|
|
|
{Partner: "minio", ValidPartner: true},
|
|
|
|
{Partner: "Minio", ValidPartner: true},
|
|
|
|
{Partner: "Raiden Network", ValidPartner: true},
|
|
|
|
{Partner: "Raiden nEtwork", ValidPartner: true},
|
|
|
|
{Partner: "invalid-name", ValidPartner: false},
|
|
|
|
} {
|
2020-11-02 12:21:55 +00:00
|
|
|
func() {
|
|
|
|
registerData := struct {
|
2021-10-26 14:30:19 +01:00
|
|
|
FullName string `json:"fullName"`
|
|
|
|
ShortName string `json:"shortName"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Partner string `json:"partner"`
|
|
|
|
UserAgent string `json:"userAgent"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
SecretInput string `json:"secret"`
|
|
|
|
ReferrerUserID string `json:"referrerUserId"`
|
|
|
|
IsProfessional bool `json:"isProfessional"`
|
|
|
|
Position string `json:"Position"`
|
|
|
|
CompanyName string `json:"CompanyName"`
|
|
|
|
EmployeeCount string `json:"EmployeeCount"`
|
|
|
|
SignupPromoCode string `json:"signupPromoCode"`
|
2020-11-02 12:21:55 +00:00
|
|
|
}{
|
2021-10-26 14:30:19 +01:00
|
|
|
FullName: "testuser" + strconv.Itoa(i),
|
|
|
|
ShortName: "test",
|
2022-03-30 15:23:13 +01:00
|
|
|
Email: "user@test" + strconv.Itoa(i) + ".test",
|
2021-10-26 14:30:19 +01:00
|
|
|
Partner: test.Partner,
|
|
|
|
Password: "abc123",
|
|
|
|
IsProfessional: true,
|
|
|
|
Position: "testposition",
|
|
|
|
CompanyName: "companytestname",
|
|
|
|
EmployeeCount: "0",
|
|
|
|
SignupPromoCode: "STORJ50",
|
2020-11-02 12:21:55 +00:00
|
|
|
}
|
2020-07-28 15:23:17 +01:00
|
|
|
|
2020-11-02 12:21:55 +00:00
|
|
|
jsonBody, err := json.Marshal(registerData)
|
|
|
|
require.NoError(t, err)
|
2020-07-28 15:23:17 +01:00
|
|
|
|
2021-08-26 17:48:24 +01:00
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
2021-05-14 16:05:42 +01:00
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
|
|
|
|
require.NoError(t, err)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
2020-07-28 15:23:17 +01:00
|
|
|
require.NoError(t, err)
|
2020-11-02 12:21:55 +00:00
|
|
|
defer func() {
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}()
|
2022-01-20 11:28:01 +00:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, planet.Satellites, 1)
|
|
|
|
// this works only because we configured 'nomail' above. Mail send simulator won't click to activation link.
|
2022-07-01 18:31:14 +01:00
|
|
|
_, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, registerData.Email)
|
2020-11-02 12:21:55 +00:00
|
|
|
require.NoError(t, err)
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, users, 1)
|
2022-07-01 18:31:14 +01:00
|
|
|
require.Equal(t, []byte(test.Partner), users[0].UserAgent)
|
2020-11-02 12:21:55 +00:00
|
|
|
}()
|
2020-07-28 15:23:17 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-10-21 11:52:24 +01:00
|
|
|
|
2021-08-26 17:48:24 +01:00
|
|
|
func TestAuth_Register_CORS(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
|
|
|
config.Console.OpenRegistrationEnabled = true
|
|
|
|
config.Console.RateLimit.Burst = 10
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
config.Mail.AuthType = "nomail"
|
2021-08-26 17:48:24 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
2022-07-01 18:31:14 +01:00
|
|
|
email := "user@test.com"
|
|
|
|
fullName := "testuser"
|
|
|
|
jsonBody := []byte(fmt.Sprintf(`{"email":"%s","fullName":"%s","password":"abc123","shortName":"test"}`, email, fullName))
|
2021-08-26 17:48:24 +01:00
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
|
|
|
|
require.NoError(t, err)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
// 1. OPTIONS request
|
|
|
|
// 1.1 CORS headers should not be set with origin other than storj.io or www.storj.io
|
|
|
|
req.Header.Set("Origin", "https://someexternalorigin.test")
|
|
|
|
req.Method = http.MethodOptions
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
require.Equal(t, "", resp.Header.Get("Access-Control-Allow-Origin"))
|
|
|
|
require.Equal(t, "", resp.Header.Get("Access-Control-Allow-Methods"))
|
|
|
|
require.Equal(t, "", resp.Header.Get("Access-Control-Allow-Headers"))
|
|
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
|
|
|
|
// 1.2 CORS headers should be set with a domain of storj.io
|
|
|
|
req.Header.Set("Origin", "https://storj.io")
|
|
|
|
resp, err = http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
require.Equal(t, "https://storj.io", resp.Header.Get("Access-Control-Allow-Origin"))
|
|
|
|
require.Equal(t, "POST, OPTIONS", resp.Header.Get("Access-Control-Allow-Methods"))
|
|
|
|
allowedHeaders := strings.Split(resp.Header.Get("Access-Control-Allow-Headers"), ", ")
|
|
|
|
require.ElementsMatch(t, allowedHeaders, []string{
|
|
|
|
"Content-Type",
|
|
|
|
"Content-Length",
|
|
|
|
"Accept",
|
|
|
|
"Accept-Encoding",
|
|
|
|
"X-CSRF-Token",
|
|
|
|
"Authorization",
|
|
|
|
})
|
|
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
|
|
|
|
// 1.3 CORS headers should be set with a domain of www.storj.io
|
|
|
|
req.Header.Set("Origin", "https://www.storj.io")
|
|
|
|
resp, err = http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
require.Equal(t, "https://www.storj.io", resp.Header.Get("Access-Control-Allow-Origin"))
|
|
|
|
require.Equal(t, "POST, OPTIONS", resp.Header.Get("Access-Control-Allow-Methods"))
|
|
|
|
allowedHeaders = strings.Split(resp.Header.Get("Access-Control-Allow-Headers"), ", ")
|
|
|
|
require.ElementsMatch(t, allowedHeaders, []string{
|
|
|
|
"Content-Type",
|
|
|
|
"Content-Length",
|
|
|
|
"Accept",
|
|
|
|
"Accept-Encoding",
|
|
|
|
"X-CSRF-Token",
|
|
|
|
"Authorization",
|
|
|
|
})
|
|
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
|
|
|
|
// 2. POST request with origin www.storj.io
|
|
|
|
req.Method = http.MethodPost
|
|
|
|
resp, err = http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
2022-01-20 11:28:01 +00:00
|
|
|
defer func() {
|
|
|
|
err = resp.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}()
|
2021-08-26 17:48:24 +01:00
|
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
require.Equal(t, "https://www.storj.io", resp.Header.Get("Access-Control-Allow-Origin"))
|
|
|
|
require.Equal(t, "POST, OPTIONS", resp.Header.Get("Access-Control-Allow-Methods"))
|
|
|
|
allowedHeaders = strings.Split(resp.Header.Get("Access-Control-Allow-Headers"), ", ")
|
|
|
|
require.ElementsMatch(t, allowedHeaders, []string{
|
|
|
|
"Content-Type",
|
|
|
|
"Content-Length",
|
|
|
|
"Accept",
|
|
|
|
"Accept-Encoding",
|
|
|
|
"X-CSRF-Token",
|
|
|
|
"Authorization",
|
|
|
|
})
|
|
|
|
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, planet.Satellites, 1)
|
|
|
|
// this works only because we configured 'nomail' above. Mail send simulator won't click to activation link.
|
2022-07-01 18:31:14 +01:00
|
|
|
_, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, email)
|
2021-08-26 17:48:24 +01:00
|
|
|
require.NoError(t, err)
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, users, 1)
|
2022-07-01 18:31:14 +01:00
|
|
|
require.Equal(t, fullName, users[0].FullName)
|
2021-08-26 17:48:24 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-21 11:52:24 +01:00
|
|
|
func TestDeleteAccount(t *testing.T) {
|
2021-05-14 16:05:42 +01:00
|
|
|
ctx := testcontext.New(t)
|
2022-07-06 17:13:16 +01:00
|
|
|
log := testplanet.NewLogger(t)
|
2021-05-14 16:05:42 +01:00
|
|
|
|
2020-10-21 11:52:24 +01:00
|
|
|
// We do a black box testing because currently we don't allow to delete
|
|
|
|
// accounts through the API hence we must always return an error response.
|
|
|
|
|
|
|
|
config := &quick.Config{
|
|
|
|
Values: func(values []reflect.Value, rnd *rand.Rand) {
|
|
|
|
// TODO: use or implement a better and thorough HTTP Request random generator
|
|
|
|
|
|
|
|
var method string
|
|
|
|
switch rnd.Intn(9) {
|
|
|
|
case 0:
|
|
|
|
method = http.MethodGet
|
|
|
|
case 1:
|
|
|
|
method = http.MethodHead
|
|
|
|
case 2:
|
|
|
|
method = http.MethodPost
|
|
|
|
case 3:
|
|
|
|
method = http.MethodPut
|
|
|
|
case 4:
|
|
|
|
method = http.MethodPatch
|
|
|
|
case 5:
|
|
|
|
method = http.MethodDelete
|
|
|
|
case 6:
|
|
|
|
method = http.MethodConnect
|
|
|
|
case 7:
|
|
|
|
method = http.MethodOptions
|
|
|
|
case 8:
|
|
|
|
method = http.MethodTrace
|
|
|
|
default:
|
|
|
|
t.Fatal("unexpected random value for HTTP method selection")
|
|
|
|
}
|
|
|
|
|
|
|
|
var path string
|
|
|
|
{
|
|
|
|
|
|
|
|
val, ok := quick.Value(reflect.TypeOf(""), rnd)
|
|
|
|
require.True(t, ok, "quick.Values generator function couldn't generate a string")
|
|
|
|
path = url.PathEscape(val.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
var query string
|
|
|
|
{
|
|
|
|
nparams := rnd.Intn(27)
|
|
|
|
params := make([]string, nparams)
|
|
|
|
|
|
|
|
for i := 0; i < nparams; i++ {
|
|
|
|
val, ok := quick.Value(reflect.TypeOf(""), rnd)
|
|
|
|
require.True(t, ok, "quick.Values generator function couldn't generate a string")
|
|
|
|
param := val.String()
|
|
|
|
|
|
|
|
val, ok = quick.Value(reflect.TypeOf(""), rnd)
|
|
|
|
require.True(t, ok, "quick.Values generator function couldn't generate a string")
|
|
|
|
param += "=" + val.String()
|
|
|
|
|
|
|
|
params[i] = param
|
|
|
|
}
|
|
|
|
|
|
|
|
query = url.QueryEscape(strings.Join(params, "&"))
|
|
|
|
}
|
|
|
|
|
|
|
|
var body io.Reader
|
|
|
|
{
|
|
|
|
val, ok := quick.Value(reflect.TypeOf([]byte(nil)), rnd)
|
|
|
|
require.True(t, ok, "quick.Values generator function couldn't generate a byte slice")
|
|
|
|
body = bytes.NewReader(val.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
withQuery := ""
|
|
|
|
if len(query) > 0 {
|
|
|
|
withQuery = "?"
|
|
|
|
}
|
|
|
|
|
|
|
|
reqURL, err := url.Parse("//storj.io/" + path + withQuery + query)
|
|
|
|
require.NoError(t, err, "error when generating a random URL")
|
2021-05-14 16:05:42 +01:00
|
|
|
req, err := http.NewRequestWithContext(ctx, method, reqURL.String(), body)
|
2020-10-21 11:52:24 +01:00
|
|
|
require.NoError(t, err, "error when geneating a random request")
|
|
|
|
values[0] = reflect.ValueOf(req)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedHandler := func(_ *http.Request) (status int, body []byte) {
|
2021-07-15 22:06:23 +01:00
|
|
|
return http.StatusNotImplemented, []byte("{\"error\":\"The server is incapable of fulfilling the request\"}\n")
|
2020-10-21 11:52:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
actualHandler := func(r *http.Request) (status int, body []byte) {
|
|
|
|
rr := httptest.NewRecorder()
|
2023-01-27 21:07:32 +00:00
|
|
|
authController := consoleapi.NewAuth(log, nil, nil, nil, nil, nil, "", "", "", "", "", "")
|
2021-06-28 18:34:33 +01:00
|
|
|
authController.DeleteAccount(rr, r)
|
2020-10-21 11:52:24 +01:00
|
|
|
|
|
|
|
//nolint:bodyclose
|
|
|
|
result := rr.Result()
|
|
|
|
defer func() {
|
|
|
|
err := result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}()
|
|
|
|
|
2022-10-11 12:39:08 +01:00
|
|
|
body, err := io.ReadAll(result.Body)
|
2020-10-21 11:52:24 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return result.StatusCode, body
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
err := quick.CheckEqual(expectedHandler, actualHandler, config)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
2021-05-14 16:05:42 +01:00
|
|
|
var cerr *quick.CheckEqualError
|
|
|
|
require.True(t, errors.As(err, &cerr))
|
2020-10-21 11:52:24 +01:00
|
|
|
|
|
|
|
t.Fatalf(`DeleteAccount handler has returned a different response:
|
|
|
|
round: %d
|
|
|
|
input args: %+v
|
|
|
|
expected response:
|
|
|
|
status code: %d
|
|
|
|
response body: %s
|
|
|
|
returned response:
|
|
|
|
status code: %d
|
|
|
|
response body: %s
|
|
|
|
`, cerr.Count, cerr.In, cerr.Out1[0], cerr.Out1[1], cerr.Out2[0], cerr.Out2[1])
|
|
|
|
}
|
|
|
|
}
|
2021-07-13 18:21:16 +01:00
|
|
|
|
|
|
|
func TestMFAEndpoints(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
sat := planet.Satellites[0]
|
|
|
|
|
|
|
|
user, err := sat.AddUser(ctx, console.CreateUser{
|
|
|
|
FullName: "MFA Test User",
|
|
|
|
Email: "mfauser@mail.test",
|
|
|
|
}, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-19 10:26:18 +01:00
|
|
|
tokenInfo, err := sat.API.Console.Service.Token(ctx, console.AuthUser{Email: user.Email, Password: user.FullName})
|
2021-07-13 18:21:16 +01:00
|
|
|
require.NoError(t, err)
|
2022-07-19 10:26:18 +01:00
|
|
|
require.NotEmpty(t, tokenInfo.Token)
|
2021-07-13 18:21:16 +01:00
|
|
|
|
2021-07-20 12:34:40 +01:00
|
|
|
type data struct {
|
2021-08-16 22:23:06 +01:00
|
|
|
Passcode string `json:"passcode"`
|
|
|
|
RecoveryCode string `json:"recoveryCode"`
|
2021-07-20 12:34:40 +01:00
|
|
|
}
|
|
|
|
|
2021-08-16 22:23:06 +01:00
|
|
|
doRequest := func(urlSuffix string, passcode string, recoveryCode string) *http.Response {
|
2021-08-26 17:48:24 +01:00
|
|
|
urlLink := sat.ConsoleURL() + "/api/v0/auth/mfa" + urlSuffix
|
2021-07-13 18:21:16 +01:00
|
|
|
var buf io.Reader
|
|
|
|
|
2021-07-20 12:34:40 +01:00
|
|
|
body := &data{
|
2021-08-16 22:23:06 +01:00
|
|
|
Passcode: passcode,
|
|
|
|
RecoveryCode: recoveryCode,
|
2021-07-13 18:21:16 +01:00
|
|
|
}
|
|
|
|
|
2021-07-20 12:34:40 +01:00
|
|
|
bodyBytes, err := json.Marshal(body)
|
|
|
|
require.NoError(t, err)
|
|
|
|
buf = bytes.NewBuffer(bodyBytes)
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, urlLink, buf)
|
2021-07-13 18:21:16 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req.AddCookie(&http.Cookie{
|
|
|
|
Name: "_tokenKey",
|
|
|
|
Path: "/",
|
2022-07-19 10:26:18 +01:00
|
|
|
Value: tokenInfo.Token.String(),
|
2021-07-13 18:21:16 +01:00
|
|
|
Expires: time.Now().AddDate(0, 0, 1),
|
|
|
|
})
|
|
|
|
|
2021-07-20 12:34:40 +01:00
|
|
|
req.Header.Set("Content-Type", "application/json")
|
2021-07-13 18:21:16 +01:00
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expect failure because MFA is not enabled.
|
2021-08-16 22:23:06 +01:00
|
|
|
result := doRequest("/generate-recovery-codes", "", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusUnauthorized, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect failure due to not having generated a secret key.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/enable", "123456", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect success when generating a secret key.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/generate-secret-key", "", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
|
|
|
|
var key string
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&key)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect failure due to prodiving empty passcode.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/enable", "", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect failure due to providing invalid passcode.
|
|
|
|
badCode, err := console.NewMFAPasscode(key, time.Now().Add(time.Hour))
|
|
|
|
require.NoError(t, err)
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/enable", badCode, "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect success when providing valid passcode.
|
|
|
|
goodCode, err := console.NewMFAPasscode(key, time.Now())
|
|
|
|
require.NoError(t, err)
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/enable", goodCode, "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect 10 recovery codes to be generated.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/generate-recovery-codes", "", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
|
|
|
|
var codes []string
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&codes)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, codes, console.MFARecoveryCodeCount)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect no token due to missing passcode.
|
|
|
|
newToken, err := sat.API.Console.Service.Token(ctx, console.AuthUser{Email: user.Email, Password: user.FullName})
|
2021-08-16 22:23:06 +01:00
|
|
|
require.True(t, console.ErrMFAMissing.Has(err))
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Empty(t, newToken)
|
|
|
|
|
|
|
|
// Expect token when providing valid passcode.
|
|
|
|
newToken, err = sat.API.Console.Service.Token(ctx, console.AuthUser{
|
|
|
|
Email: user.Email,
|
|
|
|
Password: user.FullName,
|
|
|
|
MFAPasscode: goodCode,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, newToken)
|
|
|
|
|
|
|
|
// Expect no token when providing invalid recovery code.
|
|
|
|
newToken, err = sat.API.Console.Service.Token(ctx, console.AuthUser{
|
|
|
|
Email: user.Email,
|
|
|
|
Password: user.FullName,
|
|
|
|
MFARecoveryCode: "BADCODE",
|
|
|
|
})
|
2021-11-18 18:55:37 +00:00
|
|
|
require.True(t, console.ErrMFARecoveryCode.Has(err))
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Empty(t, newToken)
|
|
|
|
|
|
|
|
for _, code := range codes {
|
|
|
|
opts := console.AuthUser{
|
|
|
|
Email: user.Email,
|
|
|
|
Password: user.FullName,
|
|
|
|
MFARecoveryCode: code,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expect token when providing valid recovery code.
|
|
|
|
newToken, err = sat.API.Console.Service.Token(ctx, opts)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, newToken)
|
|
|
|
|
|
|
|
// Expect error when providing expired recovery code.
|
|
|
|
newToken, err = sat.API.Console.Service.Token(ctx, opts)
|
2021-11-18 18:55:37 +00:00
|
|
|
require.True(t, console.ErrMFARecoveryCode.Has(err))
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Empty(t, newToken)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expect failure due to disabling MFA with no passcode.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/disable", "", "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect failure due to disabling MFA with invalid passcode.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/disable", badCode, "")
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
2021-08-16 22:23:06 +01:00
|
|
|
// Expect failure when disabling due to providing both passcode and recovery code.
|
|
|
|
result = doRequest("/generate-recovery-codes", "", "")
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&codes)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
result = doRequest("/disable", goodCode, codes[0])
|
|
|
|
require.Equal(t, http.StatusConflict, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
2021-07-13 18:21:16 +01:00
|
|
|
// Expect success when disabling MFA with valid passcode.
|
2021-08-16 22:23:06 +01:00
|
|
|
result = doRequest("/disable", goodCode, "")
|
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
// Expect success when disabling MFA with valid recovery code.
|
|
|
|
result = doRequest("/generate-secret-key", "", "")
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&key)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
goodCode, err = console.NewMFAPasscode(key, time.Now())
|
|
|
|
require.NoError(t, err)
|
|
|
|
result = doRequest("/enable", goodCode, "")
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
result = doRequest("/generate-recovery-codes", "", "")
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&codes)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
|
|
|
|
result = doRequest("/disable", "", codes[0])
|
2021-07-13 18:21:16 +01:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
})
|
|
|
|
}
|
2021-07-23 21:53:19 +01:00
|
|
|
|
|
|
|
func TestResetPasswordEndpoint(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
2022-01-12 01:42:38 +00:00
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
|
|
|
config.Console.RateLimit.Burst = 10
|
|
|
|
},
|
|
|
|
},
|
2021-07-23 21:53:19 +01:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
sat := planet.Satellites[0]
|
2022-01-12 01:42:38 +00:00
|
|
|
service := sat.API.Console.Service
|
2021-07-23 21:53:19 +01:00
|
|
|
|
|
|
|
user, err := sat.AddUser(ctx, console.CreateUser{
|
|
|
|
FullName: "Test User",
|
|
|
|
Email: "test@mail.test",
|
|
|
|
}, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-01-12 01:42:38 +00:00
|
|
|
newPass := user.FullName
|
2021-07-23 21:53:19 +01:00
|
|
|
|
2022-01-12 01:42:38 +00:00
|
|
|
getNewResetToken := func() *console.ResetPasswordToken {
|
|
|
|
token, err := sat.DB.Console().ResetPasswordTokens().Create(ctx, user.ID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, token)
|
|
|
|
return token
|
|
|
|
}
|
|
|
|
|
|
|
|
tryPasswordReset := func(tokenStr, password, mfaPasscode, mfaRecoveryCode string) (int, bool) {
|
2021-08-26 17:48:24 +01:00
|
|
|
url := sat.ConsoleURL() + "/api/v0/auth/reset-password"
|
2021-07-23 21:53:19 +01:00
|
|
|
|
|
|
|
bodyBytes, err := json.Marshal(map[string]string{
|
2022-01-12 01:42:38 +00:00
|
|
|
"password": password,
|
|
|
|
"token": tokenStr,
|
|
|
|
"mfaPasscode": mfaPasscode,
|
|
|
|
"mfaRecoveryCode": mfaRecoveryCode,
|
2021-07-23 21:53:19 +01:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(bodyBytes))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
2022-01-12 01:42:38 +00:00
|
|
|
|
|
|
|
var response struct {
|
|
|
|
Code string `json:"code"`
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.ContentLength > 0 {
|
|
|
|
err = json.NewDecoder(result.Body).Decode(&response)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2021-07-23 21:53:19 +01:00
|
|
|
require.NoError(t, result.Body.Close())
|
2022-01-12 01:42:38 +00:00
|
|
|
|
|
|
|
return result.StatusCode, response.Code == "mfa_required"
|
|
|
|
}
|
|
|
|
|
|
|
|
token := getNewResetToken()
|
|
|
|
|
|
|
|
status, mfaError := tryPasswordReset("badToken", newPass, "", "")
|
|
|
|
require.Equal(t, http.StatusUnauthorized, status)
|
|
|
|
require.False(t, mfaError)
|
|
|
|
|
|
|
|
status, mfaError = tryPasswordReset(token.Secret.String(), "bad", "", "")
|
|
|
|
require.Equal(t, http.StatusBadRequest, status)
|
|
|
|
require.False(t, mfaError)
|
|
|
|
|
2022-09-06 21:55:15 +01:00
|
|
|
status, mfaError = tryPasswordReset(token.Secret.String(), string(testrand.RandAlphaNumeric(129)), "", "")
|
|
|
|
require.Equal(t, http.StatusBadRequest, status)
|
|
|
|
require.False(t, mfaError)
|
|
|
|
|
2022-01-12 01:42:38 +00:00
|
|
|
status, mfaError = tryPasswordReset(token.Secret.String(), newPass, "", "")
|
|
|
|
require.Equal(t, http.StatusOK, status)
|
|
|
|
require.False(t, mfaError)
|
|
|
|
token = getNewResetToken()
|
|
|
|
|
|
|
|
// Enable MFA.
|
2022-06-05 23:41:38 +01:00
|
|
|
userCtx, err := sat.UserContext(ctx, user.ID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
key, err := service.ResetMFASecretKey(userCtx)
|
|
|
|
require.NoError(t, err)
|
2022-01-12 01:42:38 +00:00
|
|
|
|
2022-06-05 23:41:38 +01:00
|
|
|
userCtx, err = sat.UserContext(ctx, user.ID)
|
2022-01-12 01:42:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
passcode, err := console.NewMFAPasscode(key, token.CreatedAt)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-06-05 23:41:38 +01:00
|
|
|
err = service.EnableUserMFA(userCtx, passcode, token.CreatedAt)
|
2022-01-12 01:42:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
status, mfaError = tryPasswordReset(token.Secret.String(), newPass, "", "")
|
|
|
|
require.Equal(t, http.StatusBadRequest, status)
|
|
|
|
require.True(t, mfaError)
|
2021-07-23 21:53:19 +01:00
|
|
|
|
2022-01-12 01:42:38 +00:00
|
|
|
status, mfaError = tryPasswordReset(token.Secret.String(), newPass, "", "")
|
|
|
|
require.Equal(t, http.StatusBadRequest, status)
|
|
|
|
require.True(t, mfaError)
|
2021-07-23 21:53:19 +01:00
|
|
|
})
|
|
|
|
}
|
2021-11-18 18:55:37 +00:00
|
|
|
|
|
|
|
type EmailVerifier struct {
|
|
|
|
Data consoleapi.ContextChannel
|
|
|
|
Context context.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *EmailVerifier) SendEmail(ctx context.Context, msg *post.Message) error {
|
|
|
|
body := ""
|
|
|
|
for _, part := range msg.Parts {
|
|
|
|
body += part.Content
|
|
|
|
}
|
|
|
|
return v.Data.Send(v.Context, body)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *EmailVerifier) FromAddress() post.Address {
|
|
|
|
return post.Address{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRegistrationEmail(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
sat := planet.Satellites[0]
|
2022-07-01 18:31:14 +01:00
|
|
|
email := "test@mail.test"
|
2021-11-18 18:55:37 +00:00
|
|
|
jsonBody, err := json.Marshal(map[string]interface{}{
|
|
|
|
"fullName": "Test User",
|
|
|
|
"shortName": "Test",
|
2022-07-01 18:31:14 +01:00
|
|
|
"email": email,
|
2021-11-18 18:55:37 +00:00
|
|
|
"password": "123a123",
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-01 18:31:14 +01:00
|
|
|
register := func() {
|
2021-11-18 18:55:37 +00:00
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
|
|
|
|
require.NoError(t, err)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
sender := &EmailVerifier{Context: ctx}
|
|
|
|
sat.API.Mail.Service.Sender = sender
|
|
|
|
|
|
|
|
// Registration attempts using new e-mail address should send activation e-mail.
|
2022-07-01 18:31:14 +01:00
|
|
|
register()
|
2021-11-18 18:55:37 +00:00
|
|
|
body, err := sender.Data.Get(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, body, "/activation")
|
|
|
|
|
|
|
|
// Registration attempts using existing but unverified e-mail address should send activation e-mail.
|
2022-07-01 18:31:14 +01:00
|
|
|
register()
|
2021-11-18 18:55:37 +00:00
|
|
|
body, err = sender.Data.Get(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, body, "/activation")
|
|
|
|
|
2022-07-01 18:31:14 +01:00
|
|
|
// Registration attempts using existing and verified e-mail address should send account already exists e-mail.
|
|
|
|
_, users, err := sat.DB.Console().Users().GetByEmailWithUnverified(ctx, email)
|
2021-11-18 18:55:37 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-01 18:31:14 +01:00
|
|
|
users[0].Status = console.Active
|
|
|
|
require.NoError(t, sat.DB.Console().Users().Update(ctx, users[0].ID, console.UpdateUserRequest{
|
|
|
|
Status: &users[0].Status,
|
2022-06-01 22:15:37 +01:00
|
|
|
}))
|
2021-11-18 18:55:37 +00:00
|
|
|
|
2022-07-01 18:31:14 +01:00
|
|
|
register()
|
2021-11-18 18:55:37 +00:00
|
|
|
body, err = sender.Data.Get(ctx)
|
|
|
|
require.NoError(t, err)
|
2022-07-01 18:31:14 +01:00
|
|
|
require.Contains(t, body, "/login")
|
|
|
|
require.Contains(t, body, "/forgot-password")
|
|
|
|
require.Contains(t, body, "/signup")
|
2021-11-18 18:55:37 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResendActivationEmail(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
sat := planet.Satellites[0]
|
|
|
|
usersRepo := sat.DB.Console().Users()
|
|
|
|
|
|
|
|
user, err := sat.AddUser(ctx, console.CreateUser{
|
|
|
|
FullName: "Test User",
|
|
|
|
Email: "test@mail.test",
|
|
|
|
}, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resendEmail := func() {
|
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/resend-email/" + user.Email
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBufferString(user.Email))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, result.Body.Close())
|
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
}
|
|
|
|
|
|
|
|
sender := &EmailVerifier{Context: ctx}
|
|
|
|
sat.API.Mail.Service.Sender = sender
|
|
|
|
|
|
|
|
// Expect password reset e-mail to be sent when using verified e-mail address.
|
|
|
|
resendEmail()
|
|
|
|
body, err := sender.Data.Get(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, body, "/password-recovery")
|
|
|
|
|
|
|
|
// Expect activation e-mail to be sent when using unverified e-mail address.
|
|
|
|
user.Status = console.Inactive
|
2022-06-01 22:15:37 +01:00
|
|
|
require.NoError(t, usersRepo.Update(ctx, user.ID, console.UpdateUserRequest{
|
|
|
|
Status: &user.Status,
|
|
|
|
}))
|
2021-11-18 18:55:37 +00:00
|
|
|
|
|
|
|
resendEmail()
|
|
|
|
body, err = sender.Data.Get(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, body, "/activation")
|
|
|
|
})
|
|
|
|
}
|
2022-01-19 23:45:35 +00:00
|
|
|
|
|
|
|
func TestAuth_Register_NameSpecialChars(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
|
|
|
config.Mail.AuthType = "nomail"
|
|
|
|
},
|
|
|
|
},
|
2022-01-19 23:45:35 +00:00
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
2023-01-23 19:23:32 +00:00
|
|
|
inputName := "The website has been changed to https://evil.com/login.html<> - Enter Login ' \" Details,"
|
|
|
|
filteredName := "The website has been changed to https---evil-com-login-html\\u0026lt;\\u0026gt; - Enter Login \\u0026#39; \\u0026#34; Details,"
|
2022-07-01 18:31:14 +01:00
|
|
|
email := "user@mail.test"
|
2022-01-19 23:45:35 +00:00
|
|
|
registerData := struct {
|
|
|
|
FullName string `json:"fullName"`
|
|
|
|
ShortName string `json:"shortName"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
}{
|
|
|
|
FullName: inputName,
|
|
|
|
ShortName: inputName,
|
2022-07-01 18:31:14 +01:00
|
|
|
Email: email,
|
2022-01-19 23:45:35 +00:00
|
|
|
Password: "abc123",
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonBody, err := json.Marshal(registerData)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
|
|
|
|
require.NoError(t, err)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}()
|
2022-01-20 11:28:01 +00:00
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, planet.Satellites, 1)
|
|
|
|
// this works only because we configured 'nomail' above. Mail send simulator won't click to activation link.
|
2022-07-01 18:31:14 +01:00
|
|
|
_, users, err := planet.Satellites[0].API.Console.Service.GetUserByEmailWithUnverified(ctx, email)
|
2022-01-19 23:45:35 +00:00
|
|
|
require.NoError(t, err)
|
satellite/consoleweb: fix flaky TestAuth tests
We had a lot of flaky test failures from TestAuth. The error message (WHICH IS NOT VISIBLE IN JEKNINS, only in tests.json):
```
FAIL: TestAuth_Register_NameSpecialChars/Postgres (1.04s)
panic: runtime error: index out of range [0] with length 0 [recovered]
panic: runtime error: index out of range [0] with length 0
goroutine 3473 [running]:
testing.tRunner.func1.2({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0x235fe40, 0xc000fe6a08})
/usr/local/go/src/runtime/panic.go:1047 +0x266
storj.io/storj/satellite/console/consoleweb/consoleapi_test.TestAuth_Register_NameSpecialChars.func1(0xc001a281a0, 0x289d650, 0xc001a30000)
/var/lib/jenkins/workspace/storj-gerrit-verify/satellite/console/consoleweb/consoleapi/auth_test.go:773 +0x785
storj.io/storj/private/testplanet.Run.func1.1({0x289c770, 0xc0001b8008})
/var/lib/jenkins/workspace/storj-gerrit-verify/private/testplanet/run.go:67 +0x732
storj.io/storj/private/testmonkit.RunWith({0x289c770, 0xc0001b8008}, {0x28d89b0, 0xc001a281a0}, {0x1, {0x0, 0x0}, {0x0, 0x0, 0x0}}, ...)
```
The root cause:
testplanet uses a simulated mail sender which clicks to all the registration links by default (async).
These tests creat links and check the unverified users, but without enough luck the mail sender may already clicks to the link which makes the user verified.
Change-Id: I17cd6bf4ae3e7adc223ec693976bb609370f0c44
2022-08-04 12:31:47 +01:00
|
|
|
require.Len(t, users, 1)
|
2022-07-01 18:31:14 +01:00
|
|
|
require.Equal(t, filteredName, users[0].FullName)
|
|
|
|
require.Equal(t, filteredName, users[0].ShortName)
|
2022-01-19 23:45:35 +00:00
|
|
|
})
|
|
|
|
}
|
2022-03-30 15:23:13 +01:00
|
|
|
|
2022-08-01 12:43:23 +01:00
|
|
|
func TestAuth_Register_ShortPartnerOrPromo(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
type registerData struct {
|
|
|
|
FullName string `json:"fullName"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Password string `json:"password"`
|
|
|
|
Partner string `json:"partner"`
|
|
|
|
SignupPromoCode string `json:"signupPromoCode"`
|
|
|
|
}
|
|
|
|
|
|
|
|
reqURL := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
|
|
|
|
|
|
|
jsonBodyCorrect, err := json.Marshal(®isterData{
|
|
|
|
FullName: "test",
|
|
|
|
Email: "user@mail.test",
|
|
|
|
Password: "abc123",
|
|
|
|
Partner: string(testrand.RandAlphaNumeric(100)),
|
|
|
|
SignupPromoCode: string(testrand.RandAlphaNumeric(100)),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(jsonBodyCorrect))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, result.StatusCode)
|
|
|
|
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
jsonBodyPartnerInvalid, err := json.Marshal(®isterData{
|
|
|
|
FullName: "test",
|
|
|
|
Email: "user1@mail.test",
|
|
|
|
Password: "abc123",
|
|
|
|
Partner: string(testrand.RandAlphaNumeric(101)),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req, err = http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(jsonBodyPartnerInvalid))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err = http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
jsonBodyPromoInvalid, err := json.Marshal(®isterData{
|
|
|
|
FullName: "test",
|
|
|
|
Email: "user1@mail.test",
|
|
|
|
Password: "abc123",
|
|
|
|
SignupPromoCode: string(testrand.RandAlphaNumeric(101)),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
req, err = http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(jsonBodyPromoInvalid))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err = http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusBadRequest, result.StatusCode)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-09-06 21:55:15 +01:00
|
|
|
func TestAuth_Register_PasswordLength(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
|
|
|
|
Reconfigure: testplanet.Reconfigure{
|
|
|
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
|
|
|
config.Console.RateLimit.Burst = 10
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
for i, tt := range []struct {
|
|
|
|
Name string
|
|
|
|
Length int
|
|
|
|
Ok bool
|
|
|
|
}{
|
|
|
|
{"Length below minimum must be rejected", 5, false},
|
|
|
|
{"Length as minimum must be accepted", 6, true},
|
|
|
|
{"Length as maximum must be accepted", 128, true},
|
|
|
|
{"Length above maximum must be rejected", 129, false},
|
|
|
|
} {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.Name, func(t *testing.T) {
|
|
|
|
jsonBody, err := json.Marshal(map[string]string{
|
|
|
|
"fullName": "test",
|
|
|
|
"email": "user" + strconv.Itoa(i) + "@mail.test",
|
|
|
|
"password": string(testrand.RandAlphaNumeric(tt.Length)),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
url := planet.Satellites[0].ConsoleURL() + "/api/v0/auth/register"
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err := http.DefaultClient.Do(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = result.Body.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
status := http.StatusOK
|
|
|
|
if !tt.Ok {
|
|
|
|
status = http.StatusBadRequest
|
|
|
|
}
|
|
|
|
require.Equal(t, status, result.StatusCode)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|