HTTP request from a C# desktop application to a Si

2019-04-04 07:23发布

问题:

I have developed a C# desktop application which makes HTTPS requests to the customers' servers (usually Documentum/SharePoint/Alfresco/NemakiWare/etc HTTPS-based servers).

Several customers have asked us to support their servers which are protected by CA SSO (new name of Siteminder).

QUESTION: What do I need to do to allow my application to send HTTPS requests (and receive responses) with CA SSO-protected servers?

  • I have developed NTLM-SSO support for our C# desktop application and it works well, but I am not sure about how to proceed for CA SSO.
  • I have asked the same question on the CA forum, but like most questions there it remains unanswered.

回答1:

To authenticate with CA SSO and then connect to the desired URL we need to access a protected resource on a web server configured to use CA SSO authentication:

  1. Requests a resource on the server, using an HTTP request.
  2. The request is received by the web server and is intercepted by the CA SSO web agent.
  3. The web agent determines whether or not the resource is protected, and if so, gathers the user’s credentials and passes them to the Policy server.
  4. The Policy server authenticates the user and verifies whether or not the authenticated user is authorized for the requested resource, based on rules and policies contained in the Policy store.
  5. After the user is authenticated and authorized, the Policy server grants access to the protected resources.

This is accomplished with the following steps:

Open a connection (HTTP request in this case) to the URI of the protected resource. Since the request has not yet been authenticated, the CA SSO agent will issue a redirect to a login page. In the code, AllowAutoRedirect is set to false. This is important as the redirect URL will be required for the subsequent POST of login data in step 3 below. If AllowAutoRedirect were True, the response would not include a Location header and the subsequent POST would be made to the original URL, which would then redirect to the login page again. However, a POST occurs between a client and the server, any POST data carried in the payload of the request of step 3 will be lost during the redirect.

Dim request As HttpWebRequest
Dim response As HttpWebResponse
Dim url As String = PROTECTED_URL

request = WebRequest.Create(url)
request.AllowAutoRedirect = False
response = request.GetResponse

' make sure we have a valid response
If response.StatusCode <> HttpStatusCode.Found Then
    Throw New InvalidProgramException
End If

' get the login page
url = response.Headers("Location")
request = WebRequest.Create(url)
request.AllowAutoRedirect = False
response = request.GetResponse

The next step involves creating an HTTPS request that POSTs all the form data, including userid and password, back to the server. The purpose of an authentication agent is to verify a user’s identity by validating their userid and password. Thus, their URLs naturally use SSL (secure sockets layer) and are encrypted for us, so we do not required further encryption in our program. However, the formatting of the POST data is interesting in as much as there are two alternatives. The sample program uses the simpler approach of setting the content type to application/x-www-form-urlencoded. Here the POST data is formatted similar to a query string and sent as part of the next request.

Dim postData As String

postData = ""
For Each inputName As String In tags.Keys
    If inputName.Substring(0, 2).ToLower = "sm" Then
        postData &= inputName & "=" & _
                    HttpUtility.UrlEncode(tags(inputName)) & "&"
    End If
Next
postData += "postpreservationdata=&"
postData += "USER=" + HttpUtility.UrlEncode(USERNAME) & "&"
postData += "PASSWORD=" + HttpUtility.UrlEncode(PASSWORD)

request = WebRequest.Create(url)
cookies = New CookieContainer
request.CookieContainer = cookies
request.ContentType = FORM_CONTENT_TYPE
request.ContentLength = postData.Length
request.Method = POST_METHOD
request.AllowAutoRedirect = False   ' Important

Dim sw As StreamWriter = New StreamWriter(request.GetRequestStream())
sw.Write(postData)
sw.Flush()
sw.Close()

response = request.GetResponse


回答2:

Same idea as Mohit's answer, but it can be done with a much simpler code:

        //Make initial request for SM to give you some cookies and the authentication URI
        RestClient client = new RestClient("http://theResourceDomain/myApp");
        client.CookieContainer = new CookieContainer();
        IRestResponse response = client.Get(new RestRequest("someProduct/orders"));

        //Now add credentials.
        client.Authenticator = new HttpBasicAuthenticator("username", "password");
        //Get resource from the SiteMinder URI which will redirect back to the API URI upon authentication.
        response = client.Get(new RestRequest(response.ResponseUri)); 
  • Although this uses RestSharp, it can be easily replicated using HttpClient or even HttpWebRequest.