Repository: Versent/saml2aws
Pull request #1003 (2023-03-24 02:33:16)

Add TestGetSAMLResponse


Patch:
diff --git a/mocks/Page.go b/mocks/Page.go
index ec462e9..ae18209 100644
--- a/mocks/Page.go
+++ b/mocks/Page.go
@@ -713,11 +713,11 @@ func (_m *Page) ExposeBinding(name string, binding playwright.BindingCallFunctio
 }
 
 // ExposeFunction provides a mock function with given fields: name, binding
-func (_m *Page) ExposeFunction(name string, binding func([]interface{}) interface{}) error {
+func (_m *Page) ExposeFunction(name string, binding func(...interface{}) interface{}) error {
 	ret := _m.Called(name, binding)
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(string, func([]interface{}) interface{}) error); ok {
+	if rf, ok := ret.Get(0).(func(string, func(...interface{}) interface{}) error); ok {
 		r0 = rf(name, binding)
 	} else {
 		r0 = ret.Error(0)
diff --git a/mocks/Response.go b/mocks/Response.go
new file mode 100644
index 0000000..48fa44d
--- /dev/null
+++ b/mocks/Response.go
@@ -0,0 +1,355 @@
+// Code generated by mockery v2.22.1. DO NOT EDIT.
+
+package mocks
+
+import (
+	playwright "github.com/playwright-community/playwright-go"
+	mock "github.com/stretchr/testify/mock"
+)
+
+// Response is an autogenerated mock type for the Response type
+type Response struct {
+	mock.Mock
+}
+
+// AllHeaders provides a mock function with given fields:
+func (_m *Response) AllHeaders() (map[string]string, error) {
+	ret := _m.Called()
+
+	var r0 map[string]string
+	var r1 error
+	if rf, ok := ret.Get(0).(func() (map[string]string, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() map[string]string); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(map[string]string)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Body provides a mock function with given fields:
+func (_m *Response) Body() ([]byte, error) {
+	ret := _m.Called()
+
+	var r0 []byte
+	var r1 error
+	if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() []byte); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]byte)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Finished provides a mock function with given fields:
+func (_m *Response) Finished() {
+	_m.Called()
+}
+
+// Frame provides a mock function with given fields:
+func (_m *Response) Frame() playwright.Frame {
+	ret := _m.Called()
+
+	var r0 playwright.Frame
+	if rf, ok := ret.Get(0).(func() playwright.Frame); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(playwright.Frame)
+		}
+	}
+
+	return r0
+}
+
+// HeaderValue provides a mock function with given fields: name
+func (_m *Response) HeaderValue(name string) (string, error) {
+	ret := _m.Called(name)
+
+	var r0 string
+	var r1 error
+	if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
+		return rf(name)
+	}
+	if rf, ok := ret.Get(0).(func(string) string); ok {
+		r0 = rf(name)
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	if rf, ok := ret.Get(1).(func(string) error); ok {
+		r1 = rf(name)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// HeaderValues provides a mock function with given fields: name
+func (_m *Response) HeaderValues(name string) ([]string, error) {
+	ret := _m.Called(name)
+
+	var r0 []string
+	var r1 error
+	if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok {
+		return rf(name)
+	}
+	if rf, ok := ret.Get(0).(func(string) []string); ok {
+		r0 = rf(name)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]string)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(string) error); ok {
+		r1 = rf(name)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Headers provides a mock function with given fields:
+func (_m *Response) Headers() map[string]string {
+	ret := _m.Called()
+
+	var r0 map[string]string
+	if rf, ok := ret.Get(0).(func() map[string]string); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(map[string]string)
+		}
+	}
+
+	return r0
+}
+
+// HeadersArray provides a mock function with given fields:
+func (_m *Response) HeadersArray() (playwright.HeadersArray, error) {
+	ret := _m.Called()
+
+	var r0 playwright.HeadersArray
+	var r1 error
+	if rf, ok := ret.Get(0).(func() (playwright.HeadersArray, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() playwright.HeadersArray); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(playwright.HeadersArray)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// JSON provides a mock function with given fields: v
+func (_m *Response) JSON(v interface{}) error {
+	ret := _m.Called(v)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(interface{}) error); ok {
+		r0 = rf(v)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Ok provides a mock function with given fields:
+func (_m *Response) Ok() bool {
+	ret := _m.Called()
+
+	var r0 bool
+	if rf, ok := ret.Get(0).(func() bool); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(bool)
+	}
+
+	return r0
+}
+
+// Request provides a mock function with given fields:
+func (_m *Response) Request() playwright.Request {
+	ret := _m.Called()
+
+	var r0 playwright.Request
+	if rf, ok := ret.Get(0).(func() playwright.Request); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(playwright.Request)
+		}
+	}
+
+	return r0
+}
+
+// SecurityDetails provides a mock function with given fields:
+func (_m *Response) SecurityDetails() (*playwright.ResponseSecurityDetailsResult, error) {
+	ret := _m.Called()
+
+	var r0 *playwright.ResponseSecurityDetailsResult
+	var r1 error
+	if rf, ok := ret.Get(0).(func() (*playwright.ResponseSecurityDetailsResult, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() *playwright.ResponseSecurityDetailsResult); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*playwright.ResponseSecurityDetailsResult)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// ServerAddr provides a mock function with given fields:
+func (_m *Response) ServerAddr() (*playwright.ResponseServerAddrResult, error) {
+	ret := _m.Called()
+
+	var r0 *playwright.ResponseServerAddrResult
+	var r1 error
+	if rf, ok := ret.Get(0).(func() (*playwright.ResponseServerAddrResult, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() *playwright.ResponseServerAddrResult); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*playwright.ResponseServerAddrResult)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Status provides a mock function with given fields:
+func (_m *Response) Status() int {
+	ret := _m.Called()
+
+	var r0 int
+	if rf, ok := ret.Get(0).(func() int); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(int)
+	}
+
+	return r0
+}
+
+// StatusText provides a mock function with given fields:
+func (_m *Response) StatusText() string {
+	ret := _m.Called()
+
+	var r0 string
+	if rf, ok := ret.Get(0).(func() string); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	return r0
+}
+
+// Text provides a mock function with given fields:
+func (_m *Response) Text() (string, error) {
+	ret := _m.Called()
+
+	var r0 string
+	var r1 error
+	if rf, ok := ret.Get(0).(func() (string, error)); ok {
+		return rf()
+	}
+	if rf, ok := ret.Get(0).(func() string); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// URL provides a mock function with given fields:
+func (_m *Response) URL() string {
+	ret := _m.Called()
+
+	var r0 string
+	if rf, ok := ret.Get(0).(func() string); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	return r0
+}
+
+type mockConstructorTestingTNewResponse interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewResponse creates a new instance of Response. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewResponse(t mockConstructorTestingTNewResponse) *Response {
+	mock := &Response{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}


Test patch:
diff --git a/pkg/provider/browser/browser_test.go b/pkg/provider/browser/browser_test.go
index de963a5..edd2aed 100644
--- a/pkg/provider/browser/browser_test.go
+++ b/pkg/provider/browser/browser_test.go
@@ -1,10 +1,12 @@
 package browser
 
 import (
+	"net/url"
 	"testing"
 
 	"github.com/playwright-community/playwright-go"
 	"github.com/stretchr/testify/assert"
+	"github.com/versent/saml2aws/v2/mocks"
 	"github.com/versent/saml2aws/v2/pkg/cfg"
 	"github.com/versent/saml2aws/v2/pkg/creds"
 )
@@ -26,6 +28,10 @@ var response = `
 `
 
 func TestValidate(t *testing.T) {
+	currentSAMLResponse := getSAMLResponse
+	defer func() {
+		getSAMLResponse = currentSAMLResponse
+	}()
 	getSAMLResponse = fakeSAMLResponse
 	account := &cfg.IDPAccount{
 		Headless: true,
@@ -57,3 +63,40 @@ func TestSigninRegexFail(t *testing.T) {
 	match := regex.MatchString("https://google.com/")
 	assert.False(t, match)
 }
+
+func TestGetSAMLResponse(t *testing.T) {
+	samlp := `
+	<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
+		<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
+			<samlp:Status>
+				<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+			</samlp:Status>
+			<saml:EncryptedAssertion>
+				<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Element"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/><dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/><xenc:CipherData><xenc:CipherValue>hKoNWraWb2YHo6B8ZFI5wOj8C0zdeYnQpaIE14vqe67LCy9e4Y+q7lMTRa7gNa6WZMJbkj1aQ/omsQLRVMkknKFoGD244J0Or9Ma8aXoEkQuRFyw90G4SkH5KuE6ZjUMJkMZN6xDYC+CozYiD6Pfchth/Ks64dNLJ2REau1dV/0=</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></dsig:KeyInfo>
+					<xenc:CipherData>
+						<xenc:CipherValue>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</xenc:CipherValue>
+					</xenc:CipherData>
+				</xenc:EncryptedData>
+			</saml:EncryptedAssertion>
+	</samlp:Response>
+`
+	params := url.Values{}
+	params.Add("foo1", "bar1")
+	params.Add("SAMLResponse", samlp)
+	params.Add("foo2", "bar2")
+	url := "https://google.com/"
+	page := &mocks.Page{}
+	resp := &mocks.Response{}
+	req := &mocks.Request{}
+	regex, err := signinRegex()
+	assert.Nil(t, err)
+	page.Mock.On("Goto", url).Return(resp, nil)
+	page.Mock.On("WaitForRequest", regex).Return(req)
+	req.Mock.On("PostData").Return(params.Encode(), nil)
+	loginDetails := &creds.LoginDetails{
+		URL: url,
+	}
+	samlResp, err := getSAMLResponse(page, loginDetails)
+	assert.Nil(t, err)
+	assert.Equal(t, samlp, samlResp)
+}