Update 22-09-2011: There is a more clean way to do this here
What a pain, this was. A client asked if I had some demo code for how to upload a file into SharePoint 2010. I though to my self, how hard can it be ? and went to it.
First thing you’ll run into is knowing how to even talk with SharePoint. there's a few but Google quickly lead me to SharePoint Foundation 2010 Managed Client Object Model And you download it here. That’s all nice and easy when using windows authentication or Forms based authentication. But if your using claims based authentication (like we are and Microsoft Online Services ) you wont find many examples out there.
I was struggling for a long time with this and everything I searched for kept getting me back to ClientOmAuth but its C# and I didn’t have a lot of luck with the initial copy’n’pasting to VB but after trying some other approaches that didn’t lead me anywhere good I went back to the above code and gave it a shot. So here's a VB.NET version supporting both Windows Authentication ( adfs/services/trust/13/windowstransport ) and username/password ( adfs/services/trust/13/usernamemixed ). Windows Authentication require you enable windowstransport on the STS / ADFS server.
Imports System.Security.Principal
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.Net.Security
Imports System.Net
Imports System.IO
Imports System.Text
Imports System.Xml
Public Class SPAuth
Private SPSUrl As String
Private ADFSUrl As String
Private _SAMLToken As String
Private _Username As String
Private _Password As String
Public ReadOnly Property samlUri() As Uri
Get
Return New Uri(SPSUrl)
End Get
End Property
Public ReadOnly Property SAMLToken() As String
Get
Return _SAMLToken
End Get
End Property
Public WriteOnly Property username As String
Set(value As String)
_Username = value
End Set
End Property
Public WriteOnly Property Password As String
Set(value As String)
_Password = value
End Set
End Property
Sub New(SPSUrl As String, ADFSUrl As String, username As String, password As String)
_Username = username
_Password = password
Me.SPSUrl = SPSUrl
Me.ADFSUrl = ADFSUrl
_SAMLToken = GetNewSamlToken()
End Sub
Sub New(SPSUrl As String, ADFSUrl As String)
Me.SPSUrl = SPSUrl
Me.ADFSUrl = ADFSUrl
_SAMLToken = GetNewSamlToken()
End Sub
Private Function GetNewSamlToken() As String
Dim ret As String = String.Empty
Try
Dim samlServer As String = If(SPSUrl.EndsWith("/"), SPSUrl, SPSUrl + "/")
Dim sharepointSite = New With { _
Key .Wctx = samlServer & "_layouts/Authenticate.aspx?Source=%2F", _
Key .Wtrealm = samlServer, _
Key .Wreply = samlServer & "_trust/" _
}
Dim stsServer As String = If(ADFSUrl.EndsWith("/"), ADFSUrl, ADFSUrl + "/")
Dim stsUrl As String = stsServer & "adfs/services/trust/13/windowstransport"
'get token from STS
Dim stsResponse As String = GetResponse(sharepointSite.Wreply)
'generate response to Sharepoint
Dim stringData As String = [String].Format("wa=wsignin1.0&wctx={0}&wresult={1}", System.Web.HttpUtility.UrlEncode(sharepointSite.Wctx), System.Web.HttpUtility.UrlEncode(stsResponse))
Dim sharepointRequest As HttpWebRequest = TryCast(HttpWebRequest.Create(sharepointSite.Wreply), HttpWebRequest)
sharepointRequest.Method = "POST"
sharepointRequest.ContentType = "application/x-www-form-urlencoded"
sharepointRequest.CookieContainer = New CookieContainer()
sharepointRequest.AllowAutoRedirect = False
' This is important
Dim newStream As Stream = sharepointRequest.GetRequestStream()
Dim data As Byte() = Encoding.UTF8.GetBytes(stringData)
newStream.Write(data, 0, data.Length)
newStream.Close()
Dim webResponse As HttpWebResponse = TryCast(sharepointRequest.GetResponse(), HttpWebResponse)
ret = webResponse.Cookies("FedAuth").Value
Catch ex As Exception
MessageBox.Show("Error: " + ex.Message)
End Try
Return ret
End Function
Private Function GetResponse(realm As String) As String
Dim rst As New RequestSecurityToken()
rst.RequestType = WSTrust13Constants.RequestTypes.Issue
'bearer token, no encryption
rst.AppliesTo = New EndpointAddress(realm)
'rst.KeyType = WSTrustFeb2005Constants.KeyTypes.Bearer;
rst.KeyType = WSTrust13Constants.KeyTypes.Bearer
Dim stsServer As String = If(ADFSUrl.EndsWith("/"), ADFSUrl, ADFSUrl + "/")
Dim stsUrl As String = stsServer & "adfs/services/trust/13/windowstransport"
'WSTrustFeb2005RequestSerializer trustSerializer = new WSTrustFeb2005RequestSerializer();
Dim trustSerializer As New WSTrust13RequestSerializer()
Dim binding As New WSHttpBinding()
If _Username <> "" And _Password <> "" Then
stsUrl = stsServer & "adfs/services/trust/13/usernamemixed"
binding.Security.Mode = SecurityMode.TransportWithMessageCredential
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName
binding.Security.Message.EstablishSecurityContext = False
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic
Else
binding.Security.Mode = SecurityMode.Transport
binding.Security.Message.ClientCredentialType = MessageCredentialType.None
binding.Security.Message.EstablishSecurityContext = False
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows
End If
Dim address As New EndpointAddress(stsUrl)
'WSTrustFeb2005ContractClient trustClient = new WSTrustFeb2005ContractClient(binding, address);
Dim trustClient As New WSTrust13ContractClient(binding, address)
If _Username <> "" And _Password <> "" Then
trustClient.ClientCredentials.UserName.UserName = _Username
trustClient.ClientCredentials.UserName.Password = _Password
Else
trustClient.ClientCredentials.Windows.AllowNtlm = True
trustClient.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation
trustClient.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials
End If
'MessageVersion.Default, WSTrustFeb2005Constants.Actions.Issue,
Dim response As System.ServiceModel.Channels.Message = trustClient.EndIssue(trustClient.BeginIssue(System.ServiceModel.Channels.Message.CreateMessage(MessageVersion.[Default], WSTrust13Constants.Actions.Issue, New RequestBodyWriter(trustSerializer, rst)), Nothing, Nothing))
trustClient.Close()
Dim reader As XmlDictionaryReader = response.GetReaderAtBodyContents()
Return reader.ReadOuterXml()
End Function
Public Sub clientContext_ExecutingWebRequest(sender As Object, e As Microsoft.SharePoint.Client.WebRequestEventArgs)
Dim cc As New CookieContainer
Dim samlAuth As New Cookie("FedAuth", SAMLToken)
samlAuth.Expires = DateTime.Now.AddHours(1)
samlAuth.Path = "/"
samlAuth.Secure = True
samlAuth.HttpOnly = True
samlAuth.Domain = samlUri.Host
cc.Add(samlAuth)
e.WebRequestExecutor.WebRequest.CookieContainer = cc
'e.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
End Sub
End Class
<ServiceContract()> _
Public Interface IWSTrust13Contract
<OperationContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign, Action:="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue", ReplyAction:="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal", AsyncPattern:=True)> _
Function BeginIssue(request As System.ServiceModel.Channels.Message, callback As AsyncCallback, state As Object) As IAsyncResult
Function EndIssue(asyncResult As IAsyncResult) As System.ServiceModel.Channels.Message
End Interface
Partial Public Class WSTrust13ContractClient
Inherits ClientBase(Of IWSTrust13Contract)
Implements IWSTrust13Contract
Public Sub New(binding As System.ServiceModel.Channels.Binding, remoteAddress As System.ServiceModel.EndpointAddress)
MyBase.New(binding, remoteAddress)
End Sub
Public Function BeginIssue(request As System.ServiceModel.Channels.Message, callback As System.AsyncCallback, state As Object) As System.IAsyncResult Implements IWSTrust13Contract.BeginIssue
Return MyBase.Channel.BeginIssue(request, callback, state)
End Function
Public Function EndIssue(asyncResult As System.IAsyncResult) As System.ServiceModel.Channels.Message Implements IWSTrust13Contract.EndIssue
Return MyBase.Channel.EndIssue(asyncResult)
End Function
End Class
' Dim SPAuth As New SPAuth("https://somesite.portal.domain.com", "https://adfs.domain.com")
' Use FBA, send username and password
Dim SPAuth As New SPAuth("https://somesite.portal.domain.com", "https://adfs.domain.com", "username@domain.com", "Sup3rS3cret")
Dim clientContext As New ClientContext("https://somesite.portal.domain.com/")
AddHandler clientContext.ExecutingWebRequest, AddressOf SPAuth.clientContext_ExecutingWebRequest
clientContext.Credentials = CredentialCache.DefaultCredentials
CurrentSite = clientContext.Web
clientContext.Load(CurrentSite)
clientContext.ExecuteQuery()
Ingen kommentarer:
Send en kommentar