Social Icons

twitter google plus linkedin rss feed

Pages

12.1.12

About Windows Phone 7 and SharePoint authentication

Connecting the phone to our SharePoint environment was my Christmas project, and it took me a while... In the end I managed to do it and I thought it could be a good idea to share the joy. Besides, I have read a lot of blogs about this matter all of them? and I want to add my contribution to it.

Let's go to the matter. I created a class called SPAuthBridge from the code in the SDK that can be used to set up the connections to the SharePoint server.
using System;
using System.IO;
using System.Net;
using System.Text;

namespace PhoneUtils.Code
{
    public class SPAuthBridge
    {
        #region Properties
        public CookieContainer cookieJar = new CookieContainer();

        string SiteUrl, User;
        string Password; //This should be securestring, but I don't think it's available in WP7
        #endregion

        #region Constructors
        public SPAuthBridge(string SiteUrl, string User, string Password)
        {
            this.SiteUrl = SiteUrl;
            this.User = User;
            this.Password = Password;
        }
        #endregion

        #region Public Methods
        public void Authenticate()
        {
            try
            {
                if (string.IsNullOrEmpty(SiteUrl)) throw new ArgumentOutOfRangeException("The SPAuthBridge was not properly initialized");

                System.Uri authServiceUri = new Uri(string.Format("{0}/_vti_bin/authentication.asmx", SiteUrl));

                HttpWebRequest spAuthReq = HttpWebRequest.Create(authServiceUri) as HttpWebRequest;
                spAuthReq.CookieContainer = cookieJar;
                spAuthReq.Headers["SOAPAction"] = "http://schemas.microsoft.com/sharepoint/soap/Login";
                spAuthReq.ContentType = "text/xml; charset=utf-8";
                spAuthReq.Method = "POST";

                //add the soap message to the request
                spAuthReq.BeginGetRequestStream(new AsyncCallback(spAuthReqCallBack), spAuthReq);
            }
            catch
            {
                TriggerOnAuthenticated(false);
            }
        }
        #endregion

        #region Private Methods
        private void spAuthReqCallBack(IAsyncResult asyncResult)
        {
            string envelope =
                    @"<?xml version=""1.0"" encoding=""utf-8""?>
                    <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
                      <soap:Body>
                        <Login xmlns=""http://schemas.microsoft.com/sharepoint/soap/"">
                          <username>{0}</username>
                          <password>{1}</password>
                        </Login>
                      </soap:Body>
                    </soap:Envelope>";

            UTF8Encoding encoding = new UTF8Encoding();
            HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
            Stream _body = request.EndGetRequestStream(asyncResult);
            envelope = string.Format(envelope, User, Password);
            byte[] formBytes = encoding.GetBytes(envelope);

            _body.Write(formBytes, 0, formBytes.Length);
            _body.Close();

            request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
        }

        private void ResponseCallback(IAsyncResult asyncResult)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                Stream content = response.GetResponseStream();

                if (request != null && response != null)
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (StreamReader reader = new StreamReader(content))
                        {
                            //Put debugging code here
                            string _responseString = reader.ReadToEnd();
                            reader.Close();
                        }
                    }
                }

                //authentication complete
                TriggerOnAuthenticated(true);
            }
            catch
            {
                TriggerOnAuthenticated(false);
            }
        }
        #endregion

        #region Events
        public delegate void OnAuthenticatedHandler(bool Success);

        public event OnAuthenticatedHandler OnAuthenticated;

        protected virtual void TriggerOnAuthenticated(bool Success)
        {
            if (OnAuthenticated != null)
                OnAuthenticated(Success);
        }
        #endregion
    }
}

The way to use this class is fairly simple, you create the SPAuthBridge object, you call the Authenticate method and you are ready to go, something like this:

        StratexWP7SoapClient StratexWP7 = new StratexWP7SoapClient(); //This is my web service
        SPAuthBridge SharePointAuth;

        public MainPage()
        {
            InitializeComponent();

            (...)

            SharePointAuth = new SPAuthBridge(SiteUrl, Username, Password);
            SharePointAuth.OnAuthenticated += new SPAuthBridge.OnAuthenticatedHandler(SharePointAuth_OnAuthenticated);

            if (!string.IsNullOrEmpty(Password))
                SharePointAuth.Authenticate();
            else
                MessageBox.Show("The application should be configured before use.");
        }

        void SharePointAuth_OnAuthenticated(bool Success)
        {
            if (!Success)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    { MessageBox.Show("There was an error on the authentication procedure. Please check the configuration."); });

                return;
            }

            StratexWP7.CookieContainer = SharePointAuth.cookieJar; //This is all you have to do to connect your web service. \m/ O.O \m/

            HookEvents();

            RequestData();
        }

It looks great when it works…

clip_image002clip_image002[4]
(By the way the charts are from AmCharts)

11.1.12

Scroll bars appear in SharePoint 2010 when rendering Silverlights (Part 2)

Yes, every time you fix the height or the width of the web part it shows those ugly scrollbars.

This is not the first time I go through this, but I think this time I have solved it for good or until we get the next version of SharePoint next year…. The problem was the way I was creating the Silverlight object I was using an inline CSS style. It looked a bit like:
<object id='silverlightHost' style='height: 600px; width: 350px; margin: 0; padding: 0;' data='data:application/x-silverlight-2,' type='application/x-silverlight-2'>

After a thousand try / error experiments don’t ever think I am capable of creating a SharePoint 2010 OOTB Silverlight Web Part and copying it I changed the first line of the object to:
<object id='silverlightHost' height='600px' width='350px' data='data:application/x-silverlight-2,' type='application/x-silverlight-2' style='display:block' class='ms-dlgDisable'>
And that does the trick.

6.1.12

Creating Events in Silverlight

I have read it’s impossible in a couple of places, i don’t know if it was in the previous versions, but at least since Silverlight 3 is possible… and even more… easy.

Here is an event I use to check when an item has moved.

        #region Events
        public delegate void PositionChangeHandler(Object Sender);

        public event PositionChangeHandler PositionChangedEvent;

        protected virtual void OnPositionChanged()
        {
            if (PositionChangedEvent != null)
                PositionChangedEvent(this);
        }
        #endregion

And then in the method where I am updating the position of the item:
OnPositionChanged();

After that we can easily hook to the event from the other classes:
ParentObjective.PositionChangedEvent += new Objective.PositionChangeHandler(RelatedObjectives_PositionChangedEvent);

Nice and easy.

4.1.12

Configuring Silverlight and Web Services with SSL and Self Signed Certificates

I had a SharePoint server working perfectly or at least as well as it works in HTTP, but suddenly I felt the urge to make it HTTPS. I extended the web application etc., and I was able to access everywhere, but Oh surprise!, my silverlights were not working.

I changed the <security mode="Transport" /> in the ServiceReferences.ClientConfig but I was always getting the infamous:
An error occurred while trying to make a request to URI 'https://MyURL/_vti_bin/Service.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute.
There were a couple things to fix here.

The first thing is to add a proper self signed certificate to your site.
C:\Program Files\Microsoft SDKs\Windows\v7.1>MakeCert.exe -r -pe -n "CN=MyURL" -sky exchange -ss my
The MyURL is very important. You can’t use any self signed certificate, you should use one that suits the URL of your site.
The certificate is stored in your personal certificates, so to export it you should execute MMC.exe, and there:
File –> Add/Remove Snap-In –> Certificates –> My user account –> Finish –> OK
Then you will be able to see your certificates. The one you just created is going to be at:
Certificates – Current User –> Personal –> Certificates –> MyURL
There you should do:
Right Click –> All Tasks –> Export
And there make sure you export the private key with the certificate. This will give you as a result a .pfx file.

Now we can go to the server we want to make SSL, if we were not there yet, and copy the .pfx file somewhere we are going to remember later.

Then we open the IIS Manager select the Home node and then click in the Server Certificates image.

On the right column you should click Import and then select the .pfx file you just created. After the import you should be able to see the new certificate on the Server Certificates list.

Then we will click on the 443 site collection node (Mine is called SharePoint – 443) there, again in the right column, select Bindings. Select Https (add a new one if you don’t have it) and click edit. On the SSL Certificate drop down list select the new certificate you just uploaded.

Well, we have done de hard part, now everything is easier.

Now we’ll add the crossdomain.xml and the clientaccesspolicy.xml files to both the 80 and the 443 folders. (c:\inetpub\…\443)
The content of this files is:

crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*"/>
  <allow-http-request-headers-from domain="*" headers="SOAPAction"/>
</cross-domain-policy>

clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://*"/>
        <domain uri="https://*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

And now the even easier part. Configuring the browser.
We should navigate to https://MyURL and you will see something like this:
image

There you should continue to that web page (is recommended). And after that you’ll see URL bar turn red. Good.
Click on the Certificate Error button and then in the View certificates link:
image

After that click on:
Install Certificate… –> Next –> image & Next –> Finish –> Yes –> Ok.
Now close the browser and access again to your https://myurl. Now you should see the URL bar in white and the Lock Icon besides:
image

We are doing well. Now we’ll delete the cookies and everything else, why not?:
image

For the finishing touches we will reset the IIS and jump three times on one foot.

Now you should finally be able to connect to your SSL web services and to debug them from the Visual Studio.