Web Service Call for ADFS 2.0 Authentication

I have an ASP.NET MVC web application using ADFS 2.0 for authentication. Some of the MVC controller actions function as generic web service endpoints, receiving and serving JSON. I want to create a client application that automates some of the functionality of the application. For this purpose, I am creating an API access library that will make HTTP requests to a web service to get the job done.

I am trying to verify the authenticity. I'm using authentication for ADFS 2.0, so shouldn't I just simulate a form post with a valid username and password in order to generate a token? Instead of getting the token back, I just get the login page. I'm not sure what else I need to do to authenticate my request. My code is pasted below ... but maybe I am doing it completely wrong and something that I am not aware of?

string postData = string.Empty;
postData += "ctl00$ContentPlaceHolder1$UsernameTextBox=" + username + "&";
postData += "ctl00$ContentPlaceHolder1$PasswordTextBox=" + password;
postData += "&AuthMethod=FormsAuthentication";// Submit the data back

string url = "{url of website}";
HttpWebRequest getTokenRequest = WebRequest.Create(url) as HttpWebRequest;

getTokenRequest.CookieContainer = cookies;
getTokenRequest.ContentType = "application/x-www-form-urlencoded";
getTokenRequest.ContentLength = postData.Length;
getTokenRequest.Method = "POST";

// post the data to the request
using (StreamWriter sw = new StreamWriter(getTokenRequest.GetRequestStream()))
{
    sw.Write(postData);
    sw.Flush();
    sw.Close();
}

HttpWebResponse getTokenResponse = (HttpWebResponse)getTokenRequest.GetResponse(); 

string responseString = ResponseToString(getTokenResponse);

      

I also tried a different approach which also doesn't work. This is using WCF. I am getting the error:

The secure channel could not be opened because the security negotiation with the remote endpoint failed. This could be due to a missing or incorrect EndpointIdentity in the EndpointAddress used to create the channel. Make sure EndpointIdentity is specified or implied EndpointAddress correctly identifies the remote endpoint.

        const string relyingPartyId = "[ID]"; //ID of the relying party in AD FS
        const string adfsEndpoint = "https://[server]/adfs/services/trust/13/usernamemixed"; //url to hit - username & pw?
        const string certSubject = "[subject]"; //?

        //Setup the connection to ADFS
        var factory = new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(
            new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential), 
            new EndpointAddress(adfsEndpoint));

        factory.TrustVersion = TrustVersion.WSTrust13;

        factory.Credentials.UserName.UserName = "[un]";
        factory.Credentials.UserName.Password = "[pw]";

        //Setup the request object 
        var rst = new Microsoft.IdentityModel.Protocols.WSTrust.RequestSecurityToken
        {
            RequestType = Microsoft.IdentityModel.SecurityTokenService.RequestTypes.Issue,
            KeyType = Microsoft.IdentityModel.SecurityTokenService.KeyTypes.Bearer,
            AppliesTo = new EndpointAddress(relyingPartyId)
        };

        //Open a connection to ADFS and get a token for the logged in user
        var channel = factory.CreateChannel();

        //added to solve a trust certificate issue - bad from a security perspective
        System.Net.ServicePointManager.ServerCertificateValidationCallback +=
        (se, cert, chain, sslerror) =>
        {
            return true;
        };

        var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;

      

+3


source to share


3 answers


Most likely, the problem is as follows: string url = "{url of website}";

. And / or missing parameters in POST.

It doesn't have to be just a URL. This must be a properly formatted WS-Federation request. With time stamps, etc. And usually / sometimes (in current ADFS) this is a two step process. Normal request first and then real (uid + pwd) authentication. Both with correct WS-Fed options in their respective locations. Only uid and pwd are not enough.



Now the obvious answer, no offense is supposed to be: I suggest you take a trace of the normal login process and then compare those exact HTTP requests with yours.

0


source


ASP.NET Form Authentication uses cookies by default. After the user logs into the application, the runtime can emit a cookie in the browser. The browser will then send a cookie with each subsequent request to the application. ASP.NET will see the cookie and know that the user is already authenticated and does not need to register again.

So, you need something like this with or without WebRequest.Credentials

:



HttpWebRequest request = (HttpWebRequest)WebRequest.Create("yoururl");
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] bytes = Encoding.UTF8.GetBytes(yourpostdata);//as user pass
request.ContentLength = bytes.Length;

//or use credentials
//request.Credentials = new NetworkCredential("UserName", "PassWord");

using (Stream streamOut = request.GetRequestStream())
{
    streamOut.Write(bytes, 0, bytes.Length);
    streamOut.Close();
}

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
    Stream stream = response.GetResponseStream();
    StreamReader sr = new StreamReader(stream);
    //save cookie to reuse
    //var _cookie = response.Cookies;
    string responseString = sr.ReadToEnd()
}

      

I want to solve your problem.

0


source


You must first request ADFS to identify yourself, accept the token back, and then send the request to your application including the token inside (as a cookie).

I suggest you use Fiddler to grab the request sent from the browser and see which parts of your request are missing

0


source







All Articles