ComponentSpace

Forums



Unable to create a unit test for ReceiveSSO


Unable to create a unit test for ReceiveSSO

Author
Message
Dan Atkinson
Dan Atkinson
New Member
New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)

Group: Forum Members
Posts: 4, Visits: 62
Hi there,

I have a pretty simple unit test that fires a request to ReceiveSSO using a mocked HttpRequestBase object. However, I get back the error "There is no HTTP context.". I get a similar error when firing InitiateSSO using a mocked HttpResponseBase.

This might sound like a fairly obvious error but, since the I didn't explicitly pass a HttpContext object in, I'd like to understand what the ComponentSpace code is doing and needs the HttpContext because HttpContext isn't something that I would mock.

at ComponentSpace.SAML2.Utility.SAML.GetHttpContext()
 at ComponentSpace.SAML2.Utility.SAML.GetHttpSessionState()
 at ComponentSpace.SAML2.Data.SessionIDDelegates.GetSessionIDFromHttpSessionState()
 at ComponentSpace.SAML2.Data.AbstractSSOSessionStore.get_SessionID()
 at ComponentSpace.SAML2.Data.AbstractSSOSessionStore.CreateSessionIDForType(Type type)
 at ComponentSpace.SAML2.Data.HttpSSOSessionStore.Load(Type type)
 at ComponentSpace.SAML2.InternalSAMLServiceProvider.LoadServiceProviderSession()
 at ComponentSpace.SAML2.InternalSAMLServiceProvider..ctor()
 at ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, IDictionary`2& attributes, String& relayState)
 at Authentication.Functions.clsFunc_SamlAuth.ReceiveSingleSignOn(ReceiveSingleSignOnModel aoReceiveSingleSignOnModel, List`1 aoError_List) in D:\Development\SSO\Authentication\Functions\clsFunc_SamlAuth.vb:line 242


Whilst I don't tend to write tests for "black box" DLLs like ComponentSpace Saml, I do want to verify that, in our integration test site, the config is loaded (it is), the request gets initiated (it isn't as it also attempts to get the non-existent HttpContext), and the response can be parsed back and that we're handling errors and attributes correctly. Is there any way I can do that?

I've looked but can't find much information on either creating unit tests that verify the expected behaviour of the code, but I'd greatly appreciate it if you could also point me in the right direction for that.

Many thanks in advance.

ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
In this particular case the ASP.NET session, which stores the SAML session state, is being accessed through the HTTP context.

You will need to mock the HttpContextBase as well and set the SAML.HttpContext property.


using ComponentSpace.SAML2.Utility;

// Construct a SAMLHttpContext from the SAML request and response.
SAML.HttpContext = mockedHttpContext;



There's a SAMLHttpContext class that may be used or alternatively use your mocked object.

Regards
ComponentSpace Development
Dan Atkinson
Dan Atkinson
New Member
New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)

Group: Forum Members
Posts: 4, Visits: 62
ComponentSpace - 10/30/2019
In this particular case the ASP.NET session, which stores the SAML session state, is being accessed through the HTTP context.

You will need to mock the HttpContextBase as well and set the SAML.HttpContext property.


using ComponentSpace.SAML2.Utility;

// Construct a SAMLHttpContext from the SAML request and response.
SAML.HttpContext = mockedHttpContext;



There's a SAMLHttpContext class that may be used or alternatively use your mocked object.

Hi there,

Thank you! I've been able to seemingly get past this, albeit to a new error - "The message is not an HTTP POST.".

I have created the HttpContext mock and attached the HttpRequest to it. Below is the VB I'm using with Moq to set up the HttpRequest mock. lsRelayState and lsBase64SamlResponse are loaded in from external resources but are valid or invalid depending upon the test case. As you can see, the request method is set to POST, so it's unclear why the error is returned.

Dim lsStream = $"SAMLResponse={lsBase64SamlResponse}&RelayState={lsRelayState}"
loHttpRequestMock.Setup(Function(x) x.HttpMethod).Returns("POST")
loHttpRequestMock.Setup(Function(x) x.ContentLength).Returns(lsStream.Length)
loHttpRequestMock.Setup(Function(x) x.ContentType).Returns("application/x-www-form-urlencoded")
loHttpRequestMock.Setup(Function(x) x.Form).Returns(New NameValueCollection() From {{"SAMLResponse", lsBase64SamlResponse}, {"RelayState", lsRelayState}})
loHttpRequestMock.Setup(Function(x) x.InputStream).Returns(New IO.MemoryStream(Text.Encoding.UTF8.GetBytes(lsStream)))
loHttpContextMock.Setup(Function(x) x.Request).Returns(loHttpRequestMock.Object)
loReceiveSingleSignOnModel = New ReceiveSingleSignOnModel(loHttpContextMock.Object)

Snippet
This returns the "The message is not an HTTP POST." exception with the following trace (using 3.4.0).

at ComponentSpace.SAML2.Bindings.HTTPPostBinding.ReceiveResponse(HttpRequestBase httpRequest, XmlElement& samlMessage, String& relayState)
 at ComponentSpace.SAML2.InternalSAMLServiceProvider.ReceiveSAMLResponse(HttpRequestBase httpRequest, XmlElement& samlResponseElement, String& relayState)
 at ComponentSpace.SAML2.InternalSAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, SAMLAttribute[]& attributes, String& relayState)
 at ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, IDictionary`2& attributes, String& relayState)
 at Authentication.Functions.clsFunc_SamlAuth.ReceiveSingleSignOn(ReceiveSingleSignOnModel aoReceiveSingleSignOnModel, List`1 aoError_List) in D:\Development\SSO\Authentication\Functions\clsFunc_SamlAuth.vb:line 249


Again, any help here would be appreciated.

Many thanks.

ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
We expect the HTTP request type to be a POST. If it isn't, we throw this exception. The mocked HTTP request looks correct so I'm not sure what's going wrong here.
Please enable SAML trace and take a look at the HTTP request that's logged prior to this exception being thrown.
https://www.componentspace.com/Forums/17/Enabing-SAML-Trace
Hopefully that will provide some clues.
You're welcome to email the SAML log file to [email protected] mentioning your forum post if you'd like us to take a look at it.

Regards
ComponentSpace Development
Dan Atkinson
Dan Atkinson
New Member
New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)

Group: Forum Members
Posts: 4, Visits: 62
ComponentSpace - 10/30/2019
We expect the HTTP request type to be a POST. If it isn't, we throw this exception. The mocked HTTP request looks correct so I'm not sure what's going wrong here.
Please enable SAML trace and take a look at the HTTP request that's logged prior to this exception being thrown.
https://www.componentspace.com/Forums/17/Enabing-SAML-Trace
Hopefully that will provide some clues.
You're welcome to email the SAML log file to [email protected] mentioning your forum post if you'd like us to take a look at it.

Apologies for not replying earlier. I was on annual leave at the end of last week and I've had to look at other projects.

I added a diagnostics logger to the solution and ran the unit test again. It produced the below output (with some values redacted). Providing the SamlResponse and config in an email will not be possible at this time unfortunately.

13924/8: 05/11/2019 14:03:29: ComponentSpace.SAML2, Version=3.4.0.0, Culture=neutral, PublicKeyToken=16647a1283418145, .NET v4.0 build, Licensed.
13924/8: 05/11/2019 14:03:29: CLR: 4.0.30319.42000, OS: Microsoft Windows NT 6.2.9200.0, Account: <REDACTED>, Culture: English (United Kingdom)
13924/8: 05/11/2019 14:03:29: The SAML configuration has been set.
13924/8: 05/11/2019 14:03:29: <REDACTED>
13924/8: 05/11/2019 14:03:29: Initializing the SAML environment.
13924/8: 05/11/2019 14:03:29: The SAML environment has been successfuly initialized.
13924/8: 05/11/2019 14:03:29: The SAML_SessionId cookie with value db18c9fc-3070-4c54-99bc-5217cf1224c7 has been set.
13924/8: 05/11/2019 14:03:29: The SAML_SessionId cookie with value b6747224-d2ab-4901-9b66-efabc0a3203d has been set.
13924/8: 05/11/2019 14:03:29: Receiving an SSO response from a partner identity provider.
13924/8: 05/11/2019 14:03:29: The SAML_SessionId cookie with value b9ce464c-c261-4acb-ae7b-4f3eed22d071 has been set.
13924/8: 05/11/2019 14:03:29: Service provider session (b9ce464c-c261-4acb-ae7b-4f3eed22d071) state:
13924/8: 05/11/2019 14:03:29: Receiving response over HTTP POST.
13924/8: 05/11/2019 14:03:29: HTTP request:
POST /Request HTTP/1.1
Cache-Control: no-cache
Connection: close
Pragma: no-cache
Content-Length: 11920
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Cookie: SAML_SessionId=387d53a7-0211-4dd5-9974-3ee5be00da8b
Host: sso.mydomain.com
Referer: https://adfs.mydomain.com/
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0
origin: https://adfs.mydomain.com
dnt: 1
upgrade-insecure-requests: 1

SAMLResponse=<REDACTED>&RelayState=<REDACTED>
13924/8: 05/11/2019 14:03:29: Exception: ComponentSpace.SAML2.Exceptions.SAMLBindingException: The message is not an HTTP POST.
13924/8: 05/11/2019 14:03:29:  at ComponentSpace.SAML2.Bindings.HTTPPostBinding.ReceiveResponse(HttpRequestBase httpRequest, XmlElement& samlMessage, String& relayState)
 at ComponentSpace.SAML2.InternalSAMLServiceProvider.ReceiveSAMLResponse(HttpRequestBase httpRequest, XmlElement& samlResponseElement, String& relayState)
 at ComponentSpace.SAML2.InternalSAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, SAMLAttribute[]& attributes, String& relayState)
 at ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, IDictionary`2& attributes, String& relayState)
 at Authentication.Functions.clsFunc_SamlAuth.ReceiveSingleSignOn(ReceiveSingleSignOnModel aoReceiveSingleSignOnModel, List`1 aoError_List) in D:\Development\SSO\Authentication\Functions\clsFunc_SamlAuth.vb:line 249
 at Authentication.UnitTests.Functions.clsFunc_SamlAuthTests.ReceiveSingleSignOn_Test() in D:\Development\SSO\Authentication.UnitTests\Functions\clsFunc_SamlAuthTests.vb:line 210
 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
 at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
 at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
 at NUnit.Framework.Internal.Reflect.InvokeMethod(MethodInfo method, Object fixture, Object[] args)
 at NUnit.Framework.Internal.MethodWrapper.Invoke(Object fixture, Object[] args)
 at NUnit.Framework.Internal.Commands.TestMethodCommand.RunNonAsyncTestMethod(TestExecutionContext context)
 at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(TestExecutionContext context)
 at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
 at NUnit.Framework.Internal.Commands.TestActionCommand.Execute(TestExecutionContext context)
 at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.Execute(TestExecutionContext context)
 at NUnit.Framework.Internal.Execution.SimpleWorkItem.PerformWork()
 at NUnit.Framework.Internal.Execution.WorkItem.RunTest()
 at NUnit.Framework.Internal.Execution.WorkItem.Execute()
 at NUnit.Framework.Internal.Execution.ParallelWorkItemDispatcher.Execute(WorkItem work)
 at NUnit.Framework.Internal.Execution.ParallelWorkItemDispatcher.Dispatch(WorkItem work)
 at NUnit.Framework.Internal.Execution.CompositeWorkItem.RunChildren()
 at NUnit.Framework.Internal.Execution.CompositeWorkItem.PerformWork()
 at NUnit.Framework.Internal.Execution.WorkItem.RunTest()
 at NUnit.Framework.Internal.Execution.WorkItem.Execute()
 at NUnit.Framework.Internal.Execution.TestWorker.TestWorkerThreadProc()
 at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
 at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
 at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
 at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
 at System.Threading.ThreadHelper.ThreadStart()


I noted that, it states "Receiving response over HTTP POST", but then throws the SAMLBindingException to say that it's not. I don't know if this is any help in informing the problem.

Thanks

ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
We throw that exception if the HttpRequest.RequestType is not "POST".
Please ensure this property is set to the correct value.

Regards
ComponentSpace Development
Dan Atkinson
Dan Atkinson
New Member
New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)New Member (9 reputation)

Group: Forum Members
Posts: 4, Visits: 62
ComponentSpace - 11/5/2019
We throw that exception if the HttpRequest.RequestType is not "POST".
Please ensure this property is set to the correct value.

And boom! Suddenly my unit tests are now green! Thank you very much for your help!

I would possibly consider looking at HttpMethod instead of the RequestType but I'm sure you have good reasons for not doing that.

It would also be great if you could create some documentation for integration/unit testing with some examples of things that you may need to mock in requests/responses as it unfortunately wasn't clear what fields needed to be passed. I started mocking the InputStream, ServerVariables, and Params to no effect, and I have never needed to mock the RequestType before so I think a basic "this is what ComponentSpace expects so this is what you will need to mock in order for your tests to pass" document would be very useful for future users.

Thank you very much again for your help!

Edit: I've just had a look as a similar question on stackoverflow came from someone who queried the difference between RequestType and HttpMethod. RequestType calls HttpMethod with the former being essentially left around for backwards compatibility with ASP. So maybe I was doing the right thing but ComponentSpace uses the old method of validating the request object.

ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
Thanks for the update. I'm glad you got it working.
Fair point about documenting what's required. I'll see this is added to our backlog.
Thanks also for the SO link regarding RequestType vs HttpMethod. According to this RequestType calls HttpMethod but I think we should move to HttpMethod at some stage.

Regards
ComponentSpace Development
GO


Similar Topics


Execution: 0.000. 3 queries. Compression Enabled.
Login
Existing Account
Email Address:


Password:


Select a Forum....












Forums, Documentation & Knowledge Base - ComponentSpace


Search