none
Problem beim Einloggen im Office 365 SharePoint Online aus einer in der Cloud gehosteten Webrolle RRS feed

  • Frage

  • Hallo zusammen,

    ich habe ein Problem beim "Remote"-Einloggen beim SharePoint Online aus einer in der Cloud gehosteten Webrolle.
    Ich habe eine WebService implementiert, welcher von einer Silverlight-Anwendung aufgerufen kann, der sich als User mit Administratorrechten "silent" in im SharePoint einloggt und per SharePoint Object Model Daten aus dem SP holt. Der folgende Post bietet den Quellcode, wie dies funktioniert:
    http://www.wictorwilen.se/Post/How-to-do-active-authentication-to-Office-365-and-SharePoint-Online.aspx

    Wenn ich nun meine Applikation mit dem Cloud-Emulator in Visual Studio 2010 starte, funktioniert alles wunderbar. Mein Service loggt sich ohne Probleme ein.

    Wenn ich den selben Service nun in eine Web-Rolle in meinen Azure Account hochlade, bekomme ich folgende Fehlermeldung:

    Meldung: Unhandled Error in Silverlight Application Invoke operation 'GetGroups' failed. The remote server returned an error: (403) Forbidden. at System.Net.HttpWebRequest.GetResponse()
     at Microsoft.SharePoint.Client.SPWebRequestExecutor.Execute()
     at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
     at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
     at BTC.WFC.Dashboard.RiaServices.Web.UserInformationService.GetGroups(String username) in D:ProjekteSVN runkCORE_DevelopmentWFC-DashboardsrcDashboardServicesBTC.WFC.Dashboard.RiaServices.WebUserInformationService.cs:line 35
     at GetGroups(DomainService , Object[] )
     at System.ServiceModel.DomainServices.Server.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters)
     at System.ServiceModel.DomainServices.Server.DomainService.Invoke(InvokeDescription invokeDescription, IEnumerable`1& validationErrors)
     at System.ServiceModel.DomainServices.Hosting.InvokeOperationBehavior.OperationInvoker.InvokeCore(Object instance, Object[] inputs, Object[]& outputs)

    Gibt es irgendwelche Restriktionen oder Konfigurationseinstellung die ich anders machen muss, wenn ich den Zugriff aus der Cloud machen möchte? Kann mir irgendwer weiterhelfen?

    Hier noch einmal mein Code, der in der Cloud schiefläuft.

    public class UserInformationService : DomainService 
    {
     public List<string> GetGroupsForUser(string username)
     {   
      List<string> result = new List<string>();
       
      string url = "https://my.sharepoint.com/";
      string adminUser = "admin@my.onmicrosoft.com";
      string password = "XXX";
    
      MsOnlineClaimsHelper claimsHelper = new MsOnlineClaimsHelper(url, adminUser, password);
      using (ClientContext context = new ClientContext(url))
      {
       context.ExecutingWebRequest += claimsHelper.clientContext_ExecutingWebRequest;
    
       //Do some stuff in SP Object Model
    
      }
      return result;
     }
    }
    
    public class MsOnlineClaimsHelper
    {
     #region Properties
    
     readonly string _username;
     readonly string _password;
     readonly bool _useRtfa;
     readonly Uri _host;
    
     CookieContainer _cachedCookieContainer = null;
     DateTime _expires = DateTime.MinValue;
    
     #endregion
    
     #region Constructors
     public MsOnlineClaimsHelper(string host, string username, string password)
       : this(new Uri(host), username, password)
     {
     }
      
     public MsOnlineClaimsHelper(Uri host, string username, string password)
     {
      _host = host;
      _username = username;
      _password = password;
      _useRtfa = true;
     }
     
     public MsOnlineClaimsHelper(Uri host, string username, string password, bool useRtfa)
     {
      _host = host;
      _username = username;
      _password = password;
      _useRtfa = useRtfa;
     }
     #endregion
    
     #region Constants
     public const string office365STS = "https://login.microsoftonline.com/extSTS.srf";
     public const string office365Login = "https://login.microsoftonline.com/login.srf";
     public const string office365Metadata = "https://nexus.microsoftonline-p.com/federationmetadata/2007-06/federationmetadata.xml";
     public const string wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
     public const string wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
     private const string userAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
     #endregion
    
     class MsoCookies
     {
      public string FedAuth { get; set; }
      public string rtFa { get; set; }
      
      public DateTime Expires { get; set; }
      public Uri Host { get; set; }
     }
    
     // Method used to add cookies to CSOM
     public void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
     {
      e.WebRequestExecutor.WebRequest.CookieContainer = getCookieContainer();
      //e.WebRequestExecutor.WebRequest.UserAgent = userAgent;
     }
    
     // Creates or loads cached cookie container
     CookieContainer getCookieContainer()
     {
      if (_cachedCookieContainer == null || DateTime.Now > _expires)
      {
       // Get the SAML tokens from SPO STS (via MSO STS) using fed auth passive approach
       MsoCookies cookies = getSamlToken();
    
       if (cookies != null && !string.IsNullOrEmpty(cookies.FedAuth))
       {
        // Create cookie collection with the SAML token     
        _expires = cookies.Expires;
        CookieContainer cc = new CookieContainer();
    
        // Set the FedAuth cookie
        Cookie samlAuth = new Cookie("FedAuth", cookies.FedAuth)
        {
         Expires = cookies.Expires,
         Path = "/",
         Secure = cookies.Host.Scheme == "https",
         HttpOnly = true,
         Domain = cookies.Host.Host
        };
        cc.Add(samlAuth);
    
    
        if (_useRtfa)
        {
         // Set the rtFA (sign-out) cookie, added march 2011
         Cookie rtFa = new Cookie("rtFA", cookies.rtFa)
         {
          Expires = cookies.Expires,
          Path = "/",
          Secure = cookies.Host.Scheme == "https",
          HttpOnly = true,
          Domain = cookies.Host.Host
         };
         cc.Add(rtFa);
        }
        _cachedCookieContainer = cc;
        return cc;
       }
       return null;
      }
      return _cachedCookieContainer;
     }
    
     public CookieContainer CookieContainer
     {
      get
      {
       if (_cachedCookieContainer == null || DateTime.Now > _expires)
       {
        return getCookieContainer();
       }
       return _cachedCookieContainer;
      }
     }
    
     private MsoCookies getSamlToken()
     {
      MsoCookies ret = new MsoCookies();
    
      try
      {
       var sharepointSite = new
       {
        Wctx = office365Login,
        Wreply = _host.GetLeftPart(UriPartial.Authority) + "/_forms/default.aspx?wa=wsignin1.0"
       };
    
       //get token from STS
       string stsResponse = getResponse(office365STS, sharepointSite.Wreply);
    
       // parse the token response
       XDocument doc = XDocument.Parse(stsResponse);
    
       // get the security token
       var crypt = from result in doc.Descendants()
          where result.Name == XName.Get("BinarySecurityToken", wsse)
          select result;
    
       // get the token expiration
       var expires = from result in doc.Descendants()
           where result.Name == XName.Get("Expires", wsu)
           select result;
       ret.Expires = Convert.ToDateTime(expires.First().Value);
    
       HttpWebRequest request = createRequest(sharepointSite.Wreply);
       byte[] data = Encoding.UTF8.GetBytes(crypt.FirstOrDefault().Value);
       using (Stream stream = request.GetRequestStream())
       {
        stream.Write(data, 0, data.Length);
        stream.Close();
    
        using (HttpWebResponse webResponse = request.GetResponse() as HttpWebResponse)
        {
    
         // Handle redirect, added may 2011 for P-subscriptions
         if (webResponse.StatusCode == HttpStatusCode.MovedPermanently)
         {
          HttpWebRequest request2 = createRequest(webResponse.Headers["Location"]);
          using (Stream stream2 = request2.GetRequestStream())
          {
           stream2.Write(data, 0, data.Length);
           stream2.Close();
    
           using (HttpWebResponse webResponse2 = request2.GetResponse() as HttpWebResponse)
           {
            ret.FedAuth = webResponse2.Cookies["FedAuth"].Value;
            ret.rtFa = webResponse2.Cookies["rtFa"].Value;
            ret.Host = request2.RequestUri;
           }
          }
         }
         else
         {
          ret.FedAuth = webResponse.Cookies["FedAuth"].Value;
          ret.rtFa = webResponse.Cookies["rtFa"].Value;
          ret.Host = request.RequestUri;
         }
        }
       }
      }
      catch (Exception ex)
      {
       return null;
      }
      return ret;
     }
    
     static HttpWebRequest createRequest(string url)
     {
      HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
      request.Method = "POST";
      request.ContentType = "application/x-www-form-urlencoded";
      request.CookieContainer = new CookieContainer();
      request.AllowAutoRedirect = false; // Do NOT automatically redirect
      request.UserAgent = userAgent;
      return request;
     }
    
     private string getResponse(string stsUrl, string realm)
     {
      RequestSecurityToken rst = new RequestSecurityToken
      {
       RequestType = WSTrustFeb2005Constants.RequestTypes.Issue,
       AppliesTo = new EndpointAddress(realm),
       KeyType = WSTrustFeb2005Constants.KeyTypes.Bearer,
       TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml11TokenProfile11
      };
    
      WSTrustFeb2005RequestSerializer trustSerializer = new WSTrustFeb2005RequestSerializer();
    
      WSHttpBinding binding = new WSHttpBinding();
    
      binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
    
      binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
      binding.Security.Message.EstablishSecurityContext = false;
      binding.Security.Message.NegotiateServiceCredential = false;
    
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
    
      EndpointAddress address = new EndpointAddress(stsUrl);
    
      using (WSTrustFeb2005ContractClient trustClient = new WSTrustFeb2005ContractClient(binding, address))
      {
       trustClient.ClientCredentials.UserName.UserName = _username;
       trustClient.ClientCredentials.UserName.Password = _password;
       Message response = trustClient.EndIssue(
        trustClient.BeginIssue(
         Message.CreateMessage(
          MessageVersion.Default,
          WSTrustFeb2005Constants.Actions.Issue,
          new RequestBodyWriter(trustSerializer, rst)
         ),
         null,
         null));
       trustClient.Close();
       using (XmlDictionaryReader reader = response.GetReaderAtBodyContents())
       {
        return reader.ReadOuterXml();
       }
      }
     }
    }
    

     

    Vielen Dank und viele Grüße

    Maik

    Montag, 29. August 2011 06:04