简体   繁体   中英

.NET - Consuming HTTP services on (Domino) server with form based authentication

I am writing a utility in C# (.NET) which will use HTTP to request data from a Domino web server.

However, this server uses form based authentication, not basic HTTP authentication.

I am trying to find out how to code to do HTTP GETS/POSTS with a server that has form based authentication.

I have tried every google query I can think of, but as soon as the words "form based authentication" are in the query, all of the results only pertain to implementing the service server-side, usually in ASP.NET or Sharepoint, with no results about consuming such services from the client side.

I saw the Java code from a related question suggested here in Stack Overflow, but finding the relevant parts in foreign APIs in the other language is going to be an adventure. If there is .NET sample code or documentation available, I would really appreciate it.

I am sure someone can provide a better answer but thinking about this I would assume your server that hosts the web service has some sort of login mechanism to establish that you're authenticated. So my approach would be to first post into the login page, accept the forms authentication cookie, then continue with whatever following requests you want to make. All following requests will already have the forms authentication cookie in them.

Thank you to everyone who provided hints.

I want to share back the code I developed, in case it helps anyone else. While it is written specifically for a Domino server, it should be very easily modified for the actual field names in the post of any cookie-based authentication server.

To use the class:

  1. Create a DominoHttpSession, passing it all of the necessary properties such as server name, user name, and password.
  2. Call Authenticate
  3. Call Get or GetXml as much as required
  4. Eventually dispose of the DominoHttpSession, although it has no formal close since HTTP is technically stateless.

Limitations:

This simple version will fail of the cookie times out. It makes no attempt to determine whether login is successful or not.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;

namespace WebDomino
{

    /// <summary>
    /// A stateful (authenticated) session with a Domino server.  Current version only supports
    /// forms based authentication, and does not permit bypassing authentication.
    /// </summary>
    public class DominoHttpSession
    {
        /// <summary>
        /// Username with which to authenticate to the Domino server, must be a legal web user name.
        /// </summary>
        public string UserName { set; get; }

        /// <summary>
        /// Web password of the authenticating account.
        /// </summary>
        public string Password { set; get; }

        /// <summary>
        /// The server on which the session will exist.  At this time, all connections must use
        /// the same server.  Untested but probably will work:  switching server name before establishing
        /// a connection, as long as the authentication cookies are shared.
        /// </summary>
        public string ServerHostName { set; get; }

        /// <summary>
        /// The session cookies.  Provided in case client code wants to analyze cookie content, but
        /// more likely only used internally to hold the authentication cookie from the server.
        /// </summary>
        public CookieContainer Cookies { get { return cookies; } }

        private CookieContainer cookies = new CookieContainer();

        /// <summary>
        /// Sends an HTTP GET to the server, expecting an XML response.   
        /// </summary>
        /// <param name="url">The full url to GET; proper syntax is the responsibility of the caller.</param>
        /// <returns>The XElement representing the returned XML text</returns>
        public XElement GetXml(string url)
        {
            return XElement.Parse(Get(url));
        }

        public string Get(string url)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);

            request.CookieContainer = cookies;
            request.Method = "GET";

            using (var responseStream = request.GetResponse().GetResponseStream())
            using (var reader = new StreamReader(responseStream))
            {
                var result = reader.ReadToEnd();
                return result;                
            }                                
        }

        /// <summary>
        /// Must be called to establish the session with the server.
        /// </summary>
        public void Authenticate()
        {            
            ServicePointManager.Expect100Continue = false;

            var request = (HttpWebRequest)WebRequest.Create(String.Format("http://{0}//names.nsf?Login", ServerHostName));
            request.CookieContainer = cookies;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            using (var requestStream = request.GetRequestStream())
            using (var writer = new StreamWriter(requestStream))
            {
                writer.Write("Username={0}&Password={1}", UserName,Password);
            }

            using (var responseStream = request.GetResponse().GetResponseStream())
            using (var reader = new StreamReader(responseStream))
            {
                var result = reader.ReadToEnd();  

                // Success is assumed here--in production code it should not be
            }                                           
        }

        public ViewReader GetViewReader(string dbPath, string viewName)
        {
            return new ViewReader(this)
                   {
                       DbPath = dbPath,
                       View = viewName
                   };
        }

    }


}

During session-based authentication (what you call "form based authentication"), Domino generates a so called LTPA token (cookie) for further authentication of the user.

The easiest way to get this is by emulating a browser/user by sending the login-form with the necessary form data to the server, extracting the LTPA cookie from the servers response and using it in further requests. You could use, for example, WatiN to simplify this.

Or you can calculate the value of the cookie therfore generating it yourself. The format, ... of the LTPA cookie is easily found via Google, but it is not trivial and you need some data from the server.

If you are doing this against a server you know the admin of, you could ask him to add a Web Site rule which allows the use of basic authentication for a subset of requests, while session-based authentication is used for the rest of the Web site.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM