Skip to content

Commit

Permalink
Improve authentication tests coverage when running e2e (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris authored Dec 5, 2023
1 parent bf6e2fa commit b238963
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 74 deletions.
22 changes: 18 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,31 @@ There are two ways of running the tests:
- `make test` - runs the tests with http recordings. To run a specific test pass the `FILTER` var. Usage `make test FILTER="TestResourceServer_Read"`.
- `make test-e2e` - runs the tests against a real Auth0 tenant. To run a specific test pass the `FILTER` var. Usage `make test-record FILTER="TestResourceServer_Read"`.

To run the tests against an Auth0 tenant start by creating an
[M2M app](https://auth0.com/docs/applications/set-up-an-application/register-machine-to-machine-applications) in the
tenant, that has been authorized to request access tokens for the Management API and has all the required permissions.
### Running against an Auth0 tenant

To run the tests against an Auth0 tenant start by creating an M2M app using `auth0 apps create --name go-auth0-mgmt-tests --description "App used for go-auth0 management tests" --type m2m`, then
run `auth0 apps open <CLIENT ID>`. Authorize the Management API in the `APIs` tab and enable all permissions.

Then create a local `.env` file in the `management` folder with the following settings:

* `AUTH0_DOMAIN`: The **Domain** of the M2M app
* `AUTH0_DOMAIN`: The **Domain** of the Auth0 tenant
* `AUTH0_CLIENT_ID`: The **Client ID** of the M2M app
* `AUTH0_CLIENT_SECRET`: The **Client Secret** of the M2M app
* `AUTH0_DEBUG`: Set to `true` to call the Management API in debug mode, which dumps the HTTP requests and responses to the output


Now for the Authentication tests create another M2M app using `auth0 apps create --name go-auth0-auth-tests --description "App used for go-auth0 authentication tests" --type m2m`, then run
`auth0 apps open <CLIENT ID>`. Ensure all `Grant Types` except `Client Credentials` are enabled in `Advanced Settings`, then set the `Authentication Method` to `None` in the `Credentials` tab.

Then create a local `.env` file in the `authentication` folder with the following settings:

* `AUTH0_DOMAIN`: The **Domain** of the Auth0 tenant
* `AUTH0_CLIENT_ID`: The **Client ID** of the management M2M app
* `AUTH0_CLIENT_SECRET`: The **Client Secret** of the management M2M app
* `AUTH0_AUTH_CLIENT_ID`: The **Client ID** of the authentication M2M app
* `AUTH0_AUTH_CLIENT_SECRET`: The **Client Secret** of the authentication M2M app
* `AUTH0_DEBUG`: Set to `true` to call the Management API in debug mode, which dumps the HTTP requests and responses to the output

> **Note**
> The http test recordings can be found in the [recordings](./test/data/recordings) folder.
Expand Down
62 changes: 60 additions & 2 deletions authentication/authentication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ import (
"github.com/auth0/go-auth0/authentication/database"
"github.com/auth0/go-auth0/authentication/oauth"
"github.com/auth0/go-auth0/internal/client"
"github.com/auth0/go-auth0/management"
)

var (
domain = os.Getenv("AUTH0_DOMAIN")
clientID = os.Getenv("AUTH0_AUTH_CLIENT_ID")
clientSecret = os.Getenv("AUTH0_AUTH_CLIENT_SECRET")
mgmtClientID = os.Getenv("AUTH0_CLIENT_ID")
mgmtClientSecret = os.Getenv("AUTH0_CLIENT_SECRET")
httpRecordings = os.Getenv("AUTH0_HTTP_RECORDINGS")
httpRecordingsEnabled = false
authAPI = &Authentication{}
mgmtAPI = &management.Management{}
jwtPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8foXPIpkeLKAVfVg/W0X
steFas2XwrxAGG0lnLS3mc/cYc/pD/plsR779O8It/2YmHFWIDmCIcW57boDae/K
Expand Down Expand Up @@ -99,11 +103,20 @@ func initializeTestClient() {
context.Background(),
domain,
WithClientID(clientID),
WithIDTokenSigningAlg("HS256"),
// WithIDTokenSigningAlg("HS256"),
)
if err != nil {
log.Fatal("failed to initialize the auth api client")
}

mgmtAPI, err = management.New(
domain,
management.WithClientCredentials(context.Background(), mgmtClientID, mgmtClientSecret),
)

if err != nil {
log.Fatal("failed to initialize the management api client")
}
}

func TestAuthenticationNew(t *testing.T) {
Expand Down Expand Up @@ -188,7 +201,8 @@ func TestAuthenticationApiCallContextTimeout(t *testing.T) {
}

func TestUserInfo(t *testing.T) {
configureHTTPTestRecordings(t)
skipE2E(t)
configureHTTPTestRecordings(t, authAPI)

user, err := authAPI.UserInfo(context.Background(), "test-access-token")

Expand Down Expand Up @@ -487,3 +501,47 @@ func TestWithClockTolerance(t *testing.T) {
}, oauth.IDTokenValidationOptions{})
assert.ErrorContains(t, err, "\"iat\" not satisfied")
}

func skipE2E(t *testing.T) {
t.Helper()

if !httpRecordingsEnabled {
t.Skip("Skipped as cannot be test in E2E scenario")
}
}

func usingRecordingResponses(t *testing.T) bool {
t.Helper()

return httpRecordingsEnabled && domain == "go-auth0-dev.eu.auth0.com"
}

func givenAUser(t *testing.T) userDetails {
t.Helper()

if !usingRecordingResponses(t) {
user := &management.User{
Connection: auth0.String("Username-Password-Authentication"),
Email: auth0.String("chuck@example.com"),
Password: auth0.String("Testpassword123!"),
Username: auth0.String("test-user"),
EmailVerified: auth0.Bool(true),
VerifyEmail: auth0.Bool(false),
}

err := mgmtAPI.User.Create(context.Background(), user)
require.NoError(t, err)

t.Cleanup(func() {
err := mgmtAPI.User.Delete(context.Background(), user.GetID())
require.NoError(t, err)
})
}

return userDetails{
connection: "Username-Password-Authentication",
email: "chuck@example.com",
password: "Testpassword123!",
username: "test-user",
}
}
72 changes: 65 additions & 7 deletions authentication/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,39 @@ package authentication

import (
"context"
"fmt"
"math/rand"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/auth0/go-auth0"
"github.com/auth0/go-auth0/authentication/database"
"github.com/auth0/go-auth0/management"
)

func TestDatabaseSignUp(t *testing.T) {
configureHTTPTestRecordings(t)
configureHTTPTestRecordings(t, authAPI)

details := givenSignUpDetails(t)

userData := database.SignupRequest{
Connection: "Username-Password-Authentication",
Username: "mytestaccount",
Password: "mypassword",
Email: "mytestaccount@example.com",
Connection: details.connection,
Username: details.username,
Password: details.password,
Email: details.email,
}

createdUser, err := authAPI.Database.Signup(context.Background(), userData)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotEmpty(t, createdUser.ID)
assert.Equal(t, userData.Username, createdUser.Username)
}

func TestDatabaseChangePassword(t *testing.T) {
configureHTTPTestRecordings(t)
configureHTTPTestRecordings(t, authAPI)

resp, err := authAPI.Database.ChangePassword(context.Background(), database.ChangePasswordRequest{
Connection: "Username-Password-Authentication",
Expand All @@ -36,3 +44,53 @@ func TestDatabaseChangePassword(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "We've just sent you an email to reset your password.", resp)
}

type userDetails struct {
username string
password string
email string
connection string
}

func givenSignUpDetails(t *testing.T) *userDetails {
t.Helper()
// If we're running from recordings then we want to return the default
if usingRecordingResponses(t) {
return &userDetails{
username: "mytestaccount",
password: "mypassword",
email: "mytestaccount@example.com",
connection: "Username-Password-Authentication",
}
}

conn := givenAConnection(t)

return &userDetails{
username: fmt.Sprintf("chuck%d", rand.Intn(999)),
password: "Passwords hide their chuck",
email: fmt.Sprintf("chuck%d@example.com", rand.Intn(999)),
connection: conn.GetName(),
}
}

func givenAConnection(t *testing.T) management.Connection {
conn := &management.Connection{
Name: auth0.Stringf("Test-Connection-%d", time.Now().Unix()),
Strategy: auth0.String("auth0"),
EnabledClients: &[]string{clientID, mgmtClientID},
Options: &management.ConnectionOptions{
RequiresUsername: auth0.Bool(true),
},
}

err := mgmtAPI.Connection.Create(context.Background(), conn)
require.NoError(t, err)

t.Cleanup(func() {
err := mgmtAPI.Connection.Delete(context.Background(), conn.GetID())
require.NoError(t, err)
})

return *conn
}
12 changes: 6 additions & 6 deletions authentication/http_recordings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,28 @@ const (
recordingsDomain = "go-auth0-dev.eu.auth0.com"
)

func configureHTTPTestRecordings(t *testing.T) {
func configureHTTPTestRecordings(t *testing.T, auth *Authentication) {
t.Helper()

if !httpRecordingsEnabled {
return
}

initialTransport := authAPI.http.Transport
initialTransport := auth.http.Transport

recorderTransport, err := recorder.NewWithOptions(
&recorder.Options{
CassetteName: recordingsDIR + t.Name(),
Mode: recorder.ModeRecordOnce,
RealTransport: authAPI.http.Transport,
RealTransport: auth.http.Transport,
SkipRequestLatency: true,
},
)
require.NoError(t, err)

removeSensitiveDataFromRecordings(t, recorderTransport)

authAPI.http.Transport = recorderTransport
auth.http.Transport = recorderTransport

// Set a custom matcher that will ensure the request body matches the recording.
recorderTransport.SetMatcher(func(r *http.Request, i cassette.Request) bool {
Expand Down Expand Up @@ -104,7 +104,7 @@ func configureHTTPTestRecordings(t *testing.T) {
t.Cleanup(func() {
err := recorderTransport.Stop()
require.NoError(t, err)
authAPI.http.Transport = initialTransport
auth.http.Transport = initialTransport
})
}

Expand Down Expand Up @@ -195,7 +195,7 @@ func redactTokens(t *testing.T, i *cassette.Interaction) {
require.NoError(t, err)

tokenSet.AccessToken = "test-access-token"
tokenSet.IDToken = "test-id-token"
tokenSet.IDToken = "" // Unset IDToken rather than strip it as we don't want to verify it

if tokenSet.RefreshToken != "" {
tokenSet.RefreshToken = "test-refresh-token"
Expand Down
Loading

0 comments on commit b238963

Please sign in to comment.