Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recording of tests when using a separate authentication api instance #322

Merged
merged 6 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")
Comment on lines +34 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be AUTH0_MGMT_CLIENT_ID and AUTH0_MGMT_CLIENT_SECRET to more clearly distinguish them from their auth counterparts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd left these as matching what's used for the management tests to make it easier to reuse them (some folks might opt to set environment variables themselves instead of the .env file)

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("[email protected]"),
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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%[email protected]", 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
Loading