Getting claims to map in an R-STS scenario with ADFS 2.0
Introduction
If you have been following along, you know I have been playing with the R-STS scenario quite a bit lately. I have many, many more posts to do on this topic and I am working on these so stay tuned. Tonight I worked through a couple of hurdles in my R-STS and finally got the claims to map through ADFS 2.0. For my R-STS, I am using Dominick Baier’s StarterSTS (http://startersts.codeplex.com/) with a custom authentication provider (using a SQL user store) and then adding on some custom claims. Then I pass the resulting token into ADFS 2.0 and handle some custom claim mapping and a reissued SAML token with the final set of claims. For a long time I had been struggling to get ADFS to handle the custom claim mapping. Finally I figured out what was happening. In this post I just want to give some more information.
Details
In ADFS you can configure claim issuer trusts and relying party trusts. When you are doing an R-STS scenario, you end up with at least 2 claim issuers and at least 1 relying party. Most of the content out there is on passive federation and single STS scenarios; there is not as much information on active federation or R-STS scenarios. This makes everything more complicated. Understanding the claim procesing flow is the key. I finally started digging into some of the claim pipeline like in this article: http://technet.microsoft.com/en-us/library/ee913585(WS.10).aspx. But again, this is really more about an STS scenario rather than an R-STS scenario.
So reading this article it is easy to see that the processing order for an STS:
- Claims arrive at your STS party (Idp) which is ADFS
- Then are mapped
- Then sent onto the relying party in ADFS specified in your RST AppliesTo
- Then they are mapped
- Then sent back in the security token back from ADFS.
In R-STS, actually what happens is:
- Claims arrive at the original STS party (Idp) which in my case is the StarterSTS claim issuer
- Then are mapped
- Then sent onto the relying party in ADFS specified in your RST AppliesTo (but for the R-STS security token request)
- Then they are mapped
- Then sent back in the security token back from ADFS
I had been struggling with understanding the execution order. I had been trying to put the claim rules on the built-in “Active Directory” claim issuer because this was leg 2 of my R-STS scenario but ADFS is smart enough to pass these claims right through the built-in claim issuer. You still need to configure a pass through claim rule on both the original STS claim issuer and the relying party but everything flows through as expected.
Some hints that helped me today to accomplish this are:
- Output the claims after every token is returned. This helps you to start thinking about the pipeline.
- Start out with a claim rule in ADFS that does not evaluate incoming claims conditionally. So for example, try a hard coded claim rule like this (from http://technet.microsoft.com/en-us/library/dd807118(WS.10).aspx):
=> issue(type = “http://test/role“, value = “employee”);
The rule above just adds a hard coded claim to the resulting claims. Another helpful tip is that the rule above can issue any claim type even ones not documented in the claim descriptions of ADFS. So you can basically inject claims here without registering them with ADFS. This is both a nice flexibility and a challenge because this can hurt your debugging.
But if you are just trying to figure out where claims get injected into the pipeline, add the rule above to your relying party to just get a claim to show up on the returned token.
- Keep all the built-in Active Directory claim issuer rules in place because these are good examples. Also review the rule syntax for the rules to get a better understanding of what is happening.
Let me know if you have any questions and I will keep posting some lessons learned on my adventures with ADFS!
Thanks,
Enabling configuration for ADFS 2.0 Server Traces
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="microsoft.identityServer.service" type="Microsoft.IdentityServer.Service.Configuration.ServiceConfiguration, Microsoft.IdentityServer.Service, Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<section name="microsoft.identityServer" type="Microsoft.IdentityServer.Service.Configuration.IdentityServerConfiguration, Microsoft.IdentityServer.Service, Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
<section name="microsoft.identityServer.proxy" type="Microsoft.IdentityServer.Service.Configuration.ProxyConfigurationSection, Microsoft.IdentityServer.Service, Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
</configSections>
<microsoft.identityServer serviceMode="Server"/>
<microsoft.identityServer.proxy >
<host name="" httpPort="80" httpsPort="443" />
<proxyTrust proxyTrustRenewPeriod="240" />
</microsoft.identityServer.proxy>
<microsoft.identityServer.service>
<policyStore connectionString="Data Source=\\.\pipe\mssql$microsoft##ssee\sql\query;Initial Catalog=AdfsConfiguration;Integrated Security=True"
administrationUrl="net.tcp://localhost:1500/policy" />
<trustMonitoring enabled="true" />
</microsoft.identityServer.service>
<system.diagnostics>
<sources>
<!-- To enable WIF tracing, change the switchValue below to desired trace level - Verbose, Information, Warning, Error, Critical -->
<!-- Set TraceOutputOptions as comma separated value of the following; ProcessId ThreadId CallStack. Specify None to not include any of the optional data-->
<!-- NOTE THAT THE CHANGES TO THIS SECTION REQUIRES SERVICE RESTART TO TAKE EFFECT -->
<source name="Microsoft.IdentityModel" switchValue="Verbose">
<listeners>
<!-- <add name="ADFSWifListener" traceOutputOptions="ProcessId,ThreadId" initializeData="Wif" type="Microsoft.IdentityServer.Diagnostics.ADFSTraceListener,Microsoft.IdentityServer,Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> -->
<add name="ADFSWifListener" />
</listeners>
</source>
<!-- To enable WCF tracing, change the switchValue below to desired trace level - Verbose, Information, Warning, Error, Critical and
uncomment the system.servicemodel section below -->
<source name="System.ServiceModel" switchValue="Verbose" >
<listeners>
<!-- <add name="ADFSWcfListener" traceOutputOptions="ProcessId,ThreadId" initializeData="Wcf" type="Microsoft.IdentityServer.Diagnostics.ADFSTraceListener,Microsoft.IdentityServer,Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> -->
<add name="ADFSWcfListener" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging" switchValue="Verbose" >
<listeners>
<!-- <add name="ADFSWcfListener" traceOutputOptions="ProcessId,ThreadId" initializeData="Wcf" type="Microsoft.IdentityServer.Diagnostics.ADFSTraceListener,Microsoft.IdentityServer,Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> -->
<add name="ADFSWcfListener" />
</listeners>
</source>
</sources>
<!-- Added by Ben Cline - sharedListeners -->
<sharedListeners>
<add name="ADFSWcfListener"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="c:\temp\adfssvchost_servicemodel.svclog"
traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add name="ADFSWifListener"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="c:\temp\adfssvchost_wif.svclog"
traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
<trace autoflush="true" ></trace>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true">
</messageLogging>
</diagnostics>
</system.serviceModel>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
Some tips on Active Federation with ADFS 2.0
Introduction
At work I have been working on helping my company adopt ADFS 2.0 for a Single Sign-On initiative. I have been working on handling a WPF application’s federation with ADFS and needed to use active federation (by definition). I had been following along with Dominick Baier’s blog post at http://www.leastprivilege.com/WIFADFS2AndWCFndashPart5ServiceClientMoreFlexibilityWithWSTrustChannelFactory.aspx. Dominick’s sample seemed simple enough but there were quite a few ADFS things I had to figure out in order to make things work.
BTW, learning how WIF relates to ADFS has been quite challenging but I have found the following article to be very helpful: http://technet.microsoft.com/en-us/library/adfs2-federation-wif-application-step-by-step-guide(WS.10).aspx.
Issues
- So I downloaded the code for the post and tried running the ManualClient. This uses WSTrustChannelFactory to connect to ADFS. The base sample uses the following ADFS endpoint:
static string stsEndpoint = "https://<machine.domain>/adfs/services/trust/13/windowstransport";
The windowstransport ADFS endpoints are not enabled by default so you must enable them. When I first tried to enable the WS Trust 1.3 version it would enable but it would not allow me to enable the proxy for this. I am not sure why. Eventually I was able to get the WS Trust 1.3 endpoint enabled. So at first I switched over to using the WS Trust 2005 endpoint. I also had to change the trust version to TrustVersion.WSTrustFeb2005 in the code as well. Here is the updated code at this point:
static string stsEndpoint = "https://<machine.domain>/adfs/services/trust/2005/windowstransport"; static string svcEndpoint = "https://<machine.domain>/soapadfs/service.svc"; static void Main(string[] args) { var token = GetToken(); CallService(token); } private static SecurityToken GetToken() { var factory = new WSTrustChannelFactory( new WindowsWSTrustBinding(SecurityMode.Transport), stsEndpoint); factory.TrustVersion = TrustVersion.WSTrustFeb2005; var rst = new RequestSecurityToken { RequestType = RequestTypes.Issue, AppliesTo = new EndpointAddress(svcEndpoint), KeyType = KeyTypes.Symmetric }; var channel = factory.CreateChannel(); return channel.Issue(rst); } - So then I ran the code and it got all the way to the last line of the method GetToken() and it gives me the following nearly meaningless message back (wrapped in a FaultException):
ID3082: The request scope is not valid or is unsupported.
I was not able to find very good information on this error but I eventually found out that one of the reasons that this can occur is if you have not setup a relying party trust in ADFS for your application.
- Like with much of active federation, there is a lot less documentation out there for active federation than for passive federation. Here are the steps I went through to create an ADFS relying party for an application that does not have a federation metadata document:
a. In the ADFS 2.0 MMC, click to create a Relying Party trust.
b. On the next page of the wizard, choose to “Enter data about the relying party manually”. Click Next
c. Enter a display name, click Next
d. Choose ADFS 2.0, click Next
e. For now, do not specify an encryption certificate, click Next,
f. Do not click to enable WS-Federation passive or Web-SSO. Both of these are browser-based options that do not apply to active federation. Click Next.
g. For the relying party trust identifier, enter the endpoint reference you are using to call over WS-Trust, so I entered: <a href=”https:///soapadfs/service.svc”>https://<machine.domain>/soapadfs/service.svc
h. Click to allow all to access the relying party, click Next.
i. Click Next to move on to the Claims Authorization Wizard.
j. I just specify a Windows username pass through at this point (see the link in my introduction for how to set this up). - So then I try to run the application again and I get another annoying error message:
ID3037: The specified request failed.
Unfortunately, this is a very general one. The solution I found was to go into the relying party trust and specify the encryption certificate.
- Then I can successfully get the GetToken method to work properly. I did also notice one other variation in the ADFS configuration that can lead to a weird error. If you disable a relying party trust and try to run the application again you get the following error:
MSIS3127: The specified request failed.
To resolve this, simply enable the relying party trust.
Conclusion
I have found that much of the work with ADFS goes by the principle, “no guts, no glory,” and I wish it were easier. There seem to be a large number of errors that you can receive without a lot of helpful information for helping you resolve them. Hopefully these error resolutions will help you and I will be sure to post any other workarounds I find as I get further down the road of implementing ADFS.
Thanks,
BizTalk LOB book complete in April 2011
I have been working as a technical reviewer for a book that will be complete in April 2011 called BizTalk 2010 Line of Business Systems Integration from Packt Publishing. Pre-order is now available for the print form but some of the individual chapters are available now. Please check out this link for more information about the book: https://www.packtpub.com/microsoft-biztalk-2010-line-of-business-systems-integration/book.
It provides useful documentation of integration with Dynamics AX and CRM as well as various cloud-based services. The SAP chapters are very valuable and extend the currently available MSDN documentation for BizTalk integrations with SAP. This book would be an excellent supplement to your technical library. Thanks
BizTalk 2010 certification coming soon
Posted by clineer in BizTalk, IT Certifications on February 18, 2011
I saw today that the BizTalk 2010 certification details were posted at http://www.microsoft.com/learning/en/us/exam.aspx?ID=70-595&Locale=en-us#tab2. According to the article the exam will be available at the very end of March 2011. I know many people in the BizTalk community have been eager for another BizTalk certification test so the good news for everyone is that Microsoft listened and made this new exam. Good luck everybody!
Sorry for such a short post, I could have worked it into a tweet. Thanks
Passed 70-583 on Windows Azure
Posted by clineer in IT Certifications, Windows Azure on February 17, 2011
I just found out that I passed the Windows Azure beta exam! I took it back in November and have been waiting for such a long time to find out the results. I did hear that this exam will require re-certification every 2 years due to the constant rate of change of Azure.
For other people that have been waiting on their results, I checked the Prometric Candidate History and it changed from “Tested” to “Passed”. I had not yet gotten a “Congratulations on your new certification” email that usually comes. Apparently the results have been delayed for some reason.
— Update 2/18/2011 —
The exam is now showing on my Microsoft Transcript so the scoring process should be back to normal now.
Thanks,
Time saving PowerShell Snippets for BizTalk Part 1
Posted by clineer in BizTalk, PowerShell on February 15, 2011
Some of the beauty of using PowerShell is the ability to rapidly do things that would take a long time to do in .NET code. But you can do this without opening Visual Studio. I have found many uses for PowerShell in working with BizTalk. One area it comes in handy is working with BizTalk binding files. I know you can just use the ExplorerOM but this is painful due to its 32-bit limitations. A frequent pain-point in deploying across environments is needing to create external artifacts for supporting your BizTalk ports.
So for example you use MSMQ and need to create all the queues that your ports refer to. Or directories for all the FILE ports you use. It is nice to just include some more PowerShell to handle this and just rest assured the external artifact will get created when you deploy your BizTalk updates. In my PowerShell code below it handles creation of folders. Enjoy!
param([string]$pathToBindingsFile,[string]$rootCreatePath)
$newroot = ""
if($rootCreatePath -ne "") {
$rootCreatePathExists = [io.file]::Exists($rootCreatePath)
if($rootCreatePathExists -eq $true) { $newroot = $rootCreatePath }
else {
Write-Host "Creating directory" $rootCreatePath
[io.directory]::CreateDirectory($rootCreatePath)
$newroot = $rootCreatePath
}
}
$bindingFileExists = [io.file]::Exists($pathToBindingsFile)
if($bindingFileExists -eq $true) {
# Read in the binding file content
$bindingContent = [xml](Get-Content $pathToBindingsFile)
$bindingContent.SelectNodes("//PrimaryTransport") | ForEach-Object {
# Only process if the port type is FILE
if ($_.TransportType.Name -eq "FILE") {
$directory = [io.path]::GetDirectoryName($_.Address)
# replace with rootCreatePath if this value exists
if ($newroot.Trim() -ne "") {
$directory = $directory.Replace($defaultRoot,$newRoot)
}
# Check if the directory exists
$directoryExists = [io.directory]::Exists($directory)
if ($directoryExists -ne $true) {
Write-Host "New directory:" $directory
[io.directory]::CreateDirectory($directory)
}
}
}
}
else {
Write-Host "Binding file does not exist:" $pathToBindingsFile
}
Integrating BizTalk 2010 with CRM 2011 Online Organization Service
Posted by clineer in BizTalk, Windows Azure on February 8, 2011
Introduction
After making the post earlier today about how to interact with the CRM 2011 Online Discovery Service I remembered this was only part of the story. After getting the security information back from the discovery service it is necessary to call the organization service to work with the entities. Some of the organization service functionality is actually new to CRM 2011.
In CRM 4 the Discovery Service existed already but some aspects of the Organization Service are different. I found that the generation of the schemas for the organization service to also be more difficult.
Walkthrough
The service URI for the organization service is https://organization.crm.dynamics.com/XRMServices/2011/Organization.svc but this only gives you part of the WSDL. If you take the WSDL from this address into Visual Studio it will not generate the BizTalk schemas successfully. In fact if you try to add a service reference using the WSDL from this address you will get an error and in the app.config will see comments mentioning that svcutil did not understand the policy assertions.
I looked at the WSDL generated from the above service reference and noticed there was a referenced WSDL file. So if you then try https://organization.crm.dynamics.com/XRMServices/2011/Organization.svc?wsdl=wsdl0, this will give you the full body of the WSDL you actually need to generate the schemas. I copied the much longer WSDL file to my Sky Drive so you can generate your schemas based off of this: http://7wsmza.bay.livefilestore.com/y1pTIOWFbPSpk8WAcLftCF5h8WDa20KbBQ2HXgATcW_iHovw3UEeT74hLQ5HyfXXLcKfAODZDV_Qbc2QqwwkqyOI9uPtvaAMb1l/CrmOrganizationServiceWsdl0.wsdl?download&psid=1. Here is the updated download with my generated artifacts: http://7wsmza.bay.livefilestore.com/y1psUis8O6hlmLvyslbbSrRU38tbauTd7zsnVexj1zVfoDkWtijWO60RoNR-2RSTrMyiSJScK7JpwpGN-s0zU4p28vuseU-4LbC/CrmDiscAndOrgSvc.zip?download&psid=1. The organization service will generate quite a few port types.
When I tried compiling after generating the schemas for the organization service, I received a large number of errors. This also occurs when adding a service reference to the organization service. I have a feeling that you may need to reference a CRM assembly to reuse the types appropriately when generating the schemas, but I do not really know how this works at this point.
Conclusion
So now you have the schemas for how to call the Discovery and the Organization Services from BizTalk. It looks like all that is left is just an orchestration and a few ports once you can get the organization service schemas to compile. Thanks!
Integrating BizTalk with CRM 2011 Online Discovery Service
Introduction
On the MSDN forums there has been quite a bit of traffic and many questions about how to integrate BizTalk with Dynamics CRM 2011. Since I did not have a local CRM 2011 environment setup I thought it would be a good time to look into whether a trial of CRM 2011 existed. Yesterday I setup a trial of BPOS to test out forms services in the cloud. I found out that there was an offer running on a free trial of Dynamics CRM Online so I joined up. This trial was nearly effortless because i was already signed up as an Azure customer through my MVP/MSDN member benefits. Here is a link to the trial offer: http://www.microsoft.com/online/dynamics-crm-online.aspx
In this post I will document some of the integration experience I have encountered from working with BizTalk and CRM 2011 for basically just a few minutes. I have been very active in discussions in the MSDN forums about how BizTalk relates to CRM 2011 so I was aware of some of the current challenges. A few people had mentioned they were having trouble generating the BizTalk schemas. So this is something I tried out and was successful doing. The bigger discussion about BizTalk and CRM 2011 revolves around the adapter used for integration. In CRM 4 there was a specialized adapter but no specialized one has been found so far for CRM 2011. As far as I can tell the intended approach is to use the WCF adapters.
My hope is that the use of the WCF adapters will enable CRM implementations to achieve high availability. This has been a perplexing and difficult for one of my customers due to known limitations in the CRM 4 adapter.
Investigation
After signing up for the CRM Online 2011 trial, I was brought to the main form for working with my CRM data, which is https://<organization>.crm.dynamics.com/mains.aspx. This form reminds me quite a bit of working with SalesForce contacts and accounts but the overall feel is much more responsive and a much richer experience. The SalesForce contact and account management features were mind numbing when I worked with them. In contrast, the CRM Online forms are invigorating and stunning.
From my previous investigation into CRM 2011 and BizTalk integration I had found the following source code example: http://msdn.microsoft.com/en-us/library/dd548513.aspx. This example shows us how to communicate with the CRM Discovery service which then provides credentials to use when contacting the organization service to work with the CRM entitites. The following line of code is the most important towards pulling out some useful artifacts for BizTalk integration:
CrmDiscoveryService discoveryService = new CrmDiscoveryService();
discoveryService.Url = String.Format("https://{0}/MSCRMServices/2007/{1}/CrmDiscoveryService.asmx",
_hostname, "Passport");
The value for the _hostname variable refers to the organization URI <organization>.crm.dynamics.com. I built up this address by hand and entered it into the browser so that I could see the service description page. So the full address would be https://organization.crm.dynamics.com/MSCRMServices/2007/Passport/CrmDiscoveryService.asmx. This gave me the service description page where I could get the WSDL for the discovery service. I copied this file to my SkyDrive so that others could use it: http://7wsmza.bay.livefilestore.com/y1p-bNDOlDXzFlgNqYiOMUq2PqTsp5qG65O1TSfh3LNNTrEh4GsUBOMosJC1FPPB25IrLxngQ9-SI3u6sOjjcdcgXm-xsS0YZq5/CrmDiscoveryService.wsdl?download&psid=1. This file is critical in generating the schemas for BizTalk. Apparently this is not a new technique for CRM - it is fairly well documented: http://msdn.microsoft.com/en-us/library/cc468422.aspx
Next I opened up my VM with BizTalk 2010 and created a new solution for the integration. I copied the WSDL file mentioned above to a location where I could use it on my VM. First I tried creating the schemas by adding a service reference to my BizTalk project. This unfortunately did not create any schemas for me but it did add the service reference successfully. So the next attempt was to Right-click on my BizTalk project and go to Add Generated Items…\Consume WCF Service. Then in the wizard I specified the WSDL file from above. This helped me to generate the schemas successfully.
The schemas that were generated looked quite a bit different from really any I had seen before. Maybe the syntax will not be new to you but I thought it looked unusual. Many of the elements in the BizTalk schema designer have brackets like you would see for an xs:Any element because they are complex types. Here is a picture of the generated schema:
The schema given above actually gives you quite a bit more detail than the service description page which just mentions the Execute method.
Conclusion
Interacting the CRM 2011 Online Discovery service is actually very easy and is quite similar to the way it was implemented in CRM 4. I zipped up the generated schemas and placed them on my SkyDrive here: http://7wsmza.bay.livefilestore.com/y1pQPSjJLtG3MTim_ZSPo-JBdU-5EkH0-g5wQ_tz1LZZadsy9-RmIAD3-K8wiN_QmTrt3wJNQFB7xkDLI0obh8Pvk6lb1vETVK0/CRMOnlineBizTalkTest.zip?download&psid=1. If you are having trouble generating the schemas you can just use mine. What has been shown here is only part of the overall solution for integrating between BizTalk and CRM 2011 Online but it gets you started nicely.
Thanks,
Using SharePoint Online for InfoPath Forms Services
Introduction
Today I thought it would be fun to do more research on what InfoPath looks like in the cloud. There had been a few hints about Forms Services running on SharePoint Online and some people were suggesting that it would only work once Office365 came out. Today I started a BPOS trial at https://mocp.microsoftonline.com/site/services/bpos/signup.aspx?offer=suite"eid=067303dd-bef3-4bc9-8f95-2b24c6dae143 and created a forms library to test out my strategies on InfoPath.
To give away the spoiler, I got it to work successfully. Apparently this is currently an unsupported feature (I think until Office365 comes out), but it does work. Here are the steps that I did to test this out. In a recent post I talked about how the license changes to MOSS 2010 no longer provide forms services as a feature when you use the standard CAL. But BPOS is relatively inexpensive so I think it provides a cost-effective replacement for the MOSS functionality. I found the documentation a little lacking on how to do this so I thought I would put together a walkthrough of how I got it to work.
Walkthrough
1. So the first thing I did was make a sample form in InfoPath:
2. Then I save it and go to Tools\Form Options to enable it to work in a browser:
3. Then I just have to go through a couple pages of the wizard to publish to a Microsoft Online site.
You have to authenticate with SharePoint Online at this point. Then the next page
Then choose the forms library from your SharePoint Online site that you want to publish the form for. In the following screenshot I show a couple forms libraries. I actually used a different form library for the later pages of this wizard called OnlineFormsLibrary.
Then you get a page that says the form was published successfully:
4. Then I wanted to show the form from my browser even though I had InfoPath installed. On the form library settings you can specify that you want the form to display as a web page which will show the forms services rendering that does not require InfoPath. Here is the form for specifying this:
5. Then you can view the form by making a new item in the forms library. Here is an example of my form being rendered through Forms Services:
Conclusion
So Forms Services does work with SharePoint Online, even with just a BPOS trial. This is exciting news. As far as I know, BizTalk cannot currently integrate with SharePoint Online for document library functionality because the WSS adapter web service does not exist in the cloud. The next thing I will try is being able to post the results from InfoPath back into a custom WCF service in the cloud. From there the data could be sent back into an on-premise hosted BizTalk server via the service bus. This whole integration feels like sending something from outer space back to earth but I feel good just knowing that at least it is possible.
