I'm programmatically trusting my yammer app through .NET. While debugging the POST request to trust an app, the responses can seemingly arbitrarily render either a 302 or a 404 as the response tries to redirect to a SharePoint MySite host.
If I during the same debug session loop my requests, I get the same type of response. I have to restart debugging to have a chance at a different response. I have tried setting minute long sleeps to ensure that time has nothing to do with which type of response I get. Same rule seem to apply: One debug session, one response type.
My question is now: What do I need to do to avoid these 404's?
Here's the fiddler responses:
THE 302 RESPONSE:
POST https://www.yammer.com/MYNETWORK/oauth2/decision?client_id=MYAPPCODE&redirect_uri=http%3a%2f%2fmy.devmachine.contoso.com&response_type=code HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: www.yammer.com
Cookie: yamtrak_id=[GUID]; _workfeed_session_id=[ID] Content-Length: 90
Expect: 100-continue
utf8=%E2%9C%93&authenticity_token=[TOKEN]=&allow=Allow
HTTP/1.1 302 Found
Server: nginx
Date: Mon, 29 Sep 2014 13:21:51 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Status: 302 Found
Location: http://my.devmachine.contoso.com?code=[CODE] X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
Cache-Control: no-cache
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
X-UA-Compatible: IE=Edge,chrome=1
Set-Cookie: yamtrak_id=[ID]; path=/; expires=Tue, 29-Sep-2015 13:21:51 GMT; secure; HttpOnly
Set-Cookie: auth_token=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT; secure
Set-Cookie: auth_token_sso=; domain=yammer.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT; secure
X-Date: 1411996911966
X-Runtime: 0.073263
7e
<html><body>You are being redirected.</body></html>
0
THE 404 RESPONSE:
POST https://www.yammer.com/MYNETWORK/oauth2/decision?client_id=MYAPPCODE&redirect_uri=http%3a%2f%2fmy.devmachine.contoso.com&response_type=code HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: www.yammer.com
Cookie: yamtrak_id=[GUID]; _workfeed_session_id=[ID]
Content-Length: 90
Expect: 100-continue
utf8=%E2%9C%93&authenticity_token=[TOKEN]=&allow=Allow
HTTP/1.1 404 Not Found
Server: nginx
Date: Mon, 29 Sep 2014 13:26:03 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Status: 404 Not Found
Cache-Control: no-cache
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
X-UA-Compatible: IE=Edge,chrome=1
X-Date: 1411997163223
X-Runtime: 0.068703
a45
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=8,chrome=1" />
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>The page you were looking for doesn't exist (404)</title>
<link href="/stylesheets/yamkit/yam.css" media="screen, projection" rel="stylesheet" type="text/css" />
<style type="text/css">
body {
...
<div id="parallax-static">
<div id="parallax-static-text">
<h1>Oops!</h2>
<h2>The page you were looking for could not be found.</h2>
Let's go back to your happy place.
</div>
</div>
...
</body>
</html>
0
I'm aware of the other yammer threads in this forum, and I'm using the new login_csrf_token cookie to authenticate, so that shouldn't be the issue.
Thanks for Reading! I'm grateful for any suggestion on how to solve this.
EDIT: I've tried setting another site (google) as my redirect url, but the alternating behaviour persists.
Found it: Turns out that sometimes the authenticity token contains plus characters (+) which needs to be URL encoded. The tokens can also contain front slashes (/) but they don't trip up the succeeding call to /session or /oauth2/decision, only plus does.
Related
I have a client that sends a simple web request to a SOAP service. It is a simple C# program that uses the WSDL file of the service to create a client. The service is hosted on IIS 8.5 and Windows Server 2012. It works fine when using anonymous authentication but it fails with Windows authentication. Both client and service are in the same domain, user permissions are also fine.
I configured IIS so that it disables all forms of authentication except Windows authentication (Negotiate, NTLM). The client is configured so that it uses Windows as the client credential type.
When I send a request I get the following error:
"The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate, NTLM'"
I then tried out a tool I found on github called "WebServiceStudio". With that tool I set the WSDL, selected my request method and it worked, even with Windows authentication.
I looked at both attempts with Wireshark and noticed that the WebServiceStudio request immediately sends the Negotiate token with the first request while my own client sends the token in the second request, which to my understanding is how Windows authentication usually works.
I tried on IIS side but nothing worked so far:
Changed authentication order (Negotiate, NTLM and NTLM, Negotiate)
Changed authentication to only Negotiate
Changed extended protection in the advanced settings (neither option made a difference)
Verified that the WindowsAuthentication and WindowsAuthenticationModule were both installed
My goal is that my own C# client can successfully authenticate with Windows authentication.
Here's the C# client's configuration:
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<client>
<endpoint address="server address" binding="basicHttpBinding"
bindingConfiguration="MyContractSoap" contract="MyContract.MyContractSoap" />
</client>
<bindings>
<basicHttpBinding>
<binding name="MyContractSoap">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
And here is the wireshark data of my client's request:
POST /ABC/ShipmentDocuments.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "ABC/DocumentShipped"
Host: sdespte3
Content-Length: 333
Expect: 100-continue
Accept-Encoding: gzip, deflate
<!-- Server rejects request and states authentication method -->
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Tue, 18 Feb 2020 10:20:01 GMT
Content-Length: 1344
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Nicht autorisiert: Zugriff aufgrund ung.ltiger Anmeldeinformationen verweigert.</title>
</head>
<body>
<div id="header"><h1>Serverfehler</h1></div>
<div id="content">
<div class="content-container"><fieldset>
<h2>401 - Nicht autorisiert: Zugriff aufgrund ung.ltiger Anmeldeinformationen verweigert.</h2>
<h3>Die angegebenen Anmeldeinformationen berechtigen Sie nicht, dieses Verzeichnis oder diese Seite anzuzeigen.</h3>
</fieldset></div>
</div>
</body>
</html>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>Request data here</s:Body></s:Envelope>
<!-- We send the negotiate token -->
POST /ABC/ShipmentDocuments.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "ABC/DocumentShipped"
Accept-Encoding: gzip, deflate
Authorization: Negotiate YIIHog...Token here
Host: abc
Content-Length: 333
Expect: 100-continue
<!-- Rejected again, unsure why -->
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Tue, 18 Feb 2020 10:20:01 GMT
Content-Length: 1344
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Nicht autorisiert: Zugriff aufgrund ung.ltiger Anmeldeinformationen verweigert.</title>
<style type="text/css">
And finally the wireshark data of the other tool that worked:
POST /ABC/ShipmentDocuments.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "ABC/DocumentShipped"
Authorization: Negotiate YIILV...Token here
Host: sdespiis1
Content-Length: 415
Expect: 100-continue
HTTP/1.1 100 Continue
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>Request body here</soap:Body></soap:Envelope>
<!-- Accepted -->
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: false
X-Powered-By: ASP.NET
WWW-Authenticate: Negotiate oYG2MIGzo... Token here
Date: Tue, 18 Feb 2020 15:24:39 GMT
Content-Length: 295
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>Body here</soap:Body></soap:Envelope>
Update: Here is the client's source code to call the service.
Program:
class Program
{
static void Main(string[] args)
{
sendWebRequest();
}
static int _orderId = 1;
static int _mandant = 1;
static string _sId = "0123456789012345678901";
static string _isShipped = "eingeliefert";
static void sendWebRequest()
{
Console.WriteLine("Start webrequest Orderid: {0}, mandant: {1}, sId: {2}, isShipped: {3}", _orderId, _mandant, _sId, _isShipped);
WebserviceManager wm = new WebserviceManager();
wm.Open();
wm.SetStateToShipped(_orderId, _mandant, _sId, _isShipped);
wm.Close();
Console.WriteLine("Webrequest erfolgreich");
}
}
WebserviceManager:
public class WebserviceManager
{
protected MyContract.MyContractSoapClient _soapClient;
public WebserviceManager()
{
}
public void Open()
{
_soapClient = createWebServiceClient();
try
{
_soapClient.Open();
}
catch (Exception ex)
{
Logging.Error("Open", ex);
throw ex;
}
Logging.Info("_soap-Client open");
}
public void Close()
{
_soapClient.Close();
}
public void SetStateToShipped(int orderNo, int mandant, string sId, string isShipped)
{
_soapClient.DocumentShipped(orderNo, mandant, sId, isShipped);
}
protected MyContract.MyContractSoapClient createWebServiceClient()
{
return new MyContract.MyContractSoapSoapClient();
}
}
So it looks like the impersonation was not properly set up. I added the following line in my client program, right after creating the client object:
protected MyContract.MyContractSoapClient createWebServiceClient()
{
var client = new MyContract.MyContractSoapSoapClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
return client;
}
And now Windows authentication works as expected!
i am having problem with getting full response from post request.
Specifically my problem is that in Fiddler i got full response(responses below) and in .NET i got only part of it.
I am using HttpClient and this is like my code looks like
var client = new HttpClient();
var response = client.PostAsync(url, content).Result;
in .NET i got this response (serialized to json)
{"Version":{"Major":1,"Minor":1,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1},"Content":{"Headers":[{"Key":"Content-Length","Value":["471"]},{"Key":"Expires","Value":["Thu, 19 Nov 1981 08:52:00 GMT"]},{"Key":"Content-Type","Value":["application/json; charset=UTF-8"]}]},"StatusCode":200,"ReasonPhrase":"OK","Headers":[{"Key":"X-Frame-Options","Value":["SAMEORIGIN"]},{"Key":"Pragma","Value":["no-cache"]},{"Key":"Cache-Control","Value":["no-store, must-revalidate, no-cache, post-check=0, pre-check=0"]},{"Key":"Date","Value":["Wed, 19 Apr 2017 22:13:15 GMT"]},{"Key":"Set-Cookie","Value":["SD_FRAMEWORK_SESSION=10ktfgcedl5rq427kvmo0sj7v4; path=/","user=abca7451088; expires=Sat, 20-May-2017 22:13:15 GMT; Max-Age=2678400; httponly","password=d30b0cc02736cf891cfca885ff5245bd; expires=Sat, 20-May-2017 22:13:15 GMT; Max-Age=2678400; httponly"]},{"Key":"Server","Value":["Apache"]},{"Key":"Connection","Value":["close"]}],"RequestMessage":{"Version":{"Major":1,"Minor":1,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1},"Content":{"Headers":[{"Key":"Content-Type","Value":["application/x-www-form-urlencoded"]},{"Key":"Content-Length","Value":["88"]}]},"Method":{"Method":"POST"},"RequestUri":"http://URL.COM/","Headers":[],"Properties":{}},"IsSuccessStatusCode":true}
but in Fiddler I got this response (in RAW view)
HTTP/1.1 200 OK
Date: Wed, 19 Apr 2017 22:13:15 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Set-Cookie: SD_FRAMEWORK_SESSION=10ktfgcedl5rq427kvmo0sj7v4; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: user=abca7451088; expires=Sat, 20-May-2017 22:13:15 GMT; Max-Age=2678400; httponly
Set-Cookie: password=d30b0cc02736cf891cfca885ff5245bd; expires=Sat, 20-May-2017 22:13:15 GMT; Max-Age=2678400; httponly
Content-Length: 471
Connection: close
Content-Type: application/json; charset=UTF-8
{"special":{"login":true,"tracking":"\n<script type=\"text\/javascript\" src=\"http:\/\/url.com\/functions.js\"><\/script>\n<script type=\"text\/javascript\">\nsetPixel ({\n'location':'SIGNUP',\n'product':'test',\n'language':'cz',\n'server-id':'lobby',\n'user-id':'340668',\n'user-email':'abca30132611#mail.col',\n'user-name':'abca7451088'\n});\n<\/script>"},"messages":{"error":[],"warning":[],"success":["V\u00edt\u00e1me V\u00e1s, abca7451088"]}}
So, how can I get that special section ("{"special":{"....") in .NET response?
Fiddler shows response content. You can get content from HttpResponseMessage using ReadAsStringAsync method of HttpContent:
var content = response.Content.ReadAsStringAsync().Result;
I have a Winform Application that I can use TCP client to connect to WCF service, but I don't know how to call its function.
I've been looking at sending SOAP-XML request to WCF service through TCP client, but always get "Bad Request" respond.
Here's my request:
POST /MyService.svc HTTP/1.1
Host: MyHost.com
Content-Type: text/xml; charset=utf-8
Content-Length: 700
SOAPAction: "http://MyHost.com/MyService/MyFunction"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action soap:must Understand="1"
xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
http://MyHost.com/MyService/MyFunction
</Action>
</soap:Header>
<soap:Body>
<MyFunction xmlns="http://MyHost.com/">
</MyFunction>
</soap:Body>
And here's response:
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 07 Jul 2015 01:32:13 GMT
Connection: close
Content-Length: 339
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Header</h2>
<hr><p>HTTP Error 400. The request has an invalid header name.</p>
</BODY></HTML>
I am using the Spring.Net Framework (spring.rest, spring.social.core and spring.social.twitter (2.x - oauth 1.0a) with c#.
The idea of the application will be for an event, people can link their twitter account to the event and as results are received for that person. The persons result it posted to their twitter account.
It will be made up of a website where users will register and give access. Then a console application which will process results (using the saved token set to post to registered users.
I have a web mvc application that asks a user to sign in and authorise an application so that it can post on behalf of the user. This information returned (token etc) is encrypted and kept in a db linked to the user. e.g. Our website - redirect to callback url - twitter - sign in +permission - back to callback url - store token info in db encrypted.
I then have a console application (eventually a service) which looks at results, when we have a result for a person with twitter account associated and permission given. We use that information to post to their account (their result).
The sign up process works fine, and i can post to the signed up person. saying they've registered. (website)
The console application initially worked to be able to post up results.
However, suddenly I am getting ( i think this is just a time frame (approx an hour) - works soon as a they register.)
"POST request for 'https://api.twitter.com/oauth/access_token' resulted in 401 - Unauthorized (Authorization Required)."
Linked to a user (in our system) - i am encrypting and storing verifier (from callback), secret and value. I then am using this to exchange for a access token to get secret and value to be able to post.
This is currently all a demo (going to 127.0.0.1) for a proof of concept.
So far only tried all this with the Spring.Social framework (c#)
When it works via console application -- RAW -
REQUEST
POST https://api.twitter.com/oauth/access_token HTTP/1.1
Accept: application/x-www-form-urlencoded,multipart/form-data,/
Authorization: OAuth oauth_consumer_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
, oauth_signature_method="HMAC-SHA1"
, oauth_timestamp="1417007918"
, oauth_nonce="1784014115"
, oauth_version="1.0"
, oauth_token="yyyyyyyyyyyyyyyyyyyyyyyyyyy"
, oauth_verifier="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
, oauth_signature="vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
Content-Type: application/x-www-form-urlencoded
Host: api.twitter.com
Content-Length: 0
Connection: Keep-Alive
RESPONSE
HTTP/1.1 200 OK
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
content-length: 167
content-security-policy: default-src https:; connect-src https:; font-src https: data:; frame-src https:; img-src https: data:; media-src https:; object-src https:; script-src 'unsafe-inline' 'unsafe-eval' https:; style-src 'unsafe-inline' https:; report-uri https://twitter.com/i/csp_report?a=NVXW433SMFUWY%3D%3D%3D&ro=false;
content-type: text/html; charset=utf-8
date: Wed, 26 Nov 2014 13:18:40 UTC
etag: "fbf12c0103c8a9a4e85476ebc4a721fb"
expires: Tue, 31 Mar 1981 05:00:00 GMT
last-modified: Wed, 26 Nov 2014 13:18:39 GMT
pragma: no-cache
server: tsa_b
set-cookie: twittersess=BAh7BzoPY3JlYXRlZF9hdGwrCAnzQOxJAToHaWQiJTZjODM4ZWMwZDg4ZjY0%250ANGFjYWE0N2M1YWU0MmMzNmZl--af2ffe955256e30da84bc52b585d7c30b6926284; domain=.twitter.com; path=/; secure; HttpOnly
set-cookie: guest_id=v1%3A141700791973784560; Domain=.twitter.com; Path=/; Expires=Fri, 25-Nov-2016 13:18:40 UTC
status: 200 OK
strict-transport-security: max-age=631138519
vary: Accept-Encoding
x-connection-hash: bd73d7f87abb9c16caef67f675d8641b
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-mid: 4e5118e4376219e001674f1292c123965885210f
x-runtime: 0.10480
x-transaction: d24c3b12ea39be37
x-ua-compatible: IE=edge,chrome=1
x-xss-protection: 1; mode=block
oauth_token=xxxxx-xxxxxxxxxxxxxxxxxxxxxx&oauth_token_secret=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy&user_id=2xxxxxxxxxxxxxx&screen_name=naxxxxxx
After about an hour(couple of hours in this instance) same code will fail.... with HTTP/1.1 401 Authorization Required - Invalid / expired Token.
REQUEST
POST https://api.twitter.com/oauth/access_token HTTP/1.1
Accept: application/x-www-form-urlencoded,multipart/form-data,*/*
Authorization: OAuth oauth_consumer_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
, oauth_signature_method="HMAC-SHA1"
, oauth_timestamp="1417018992"
, oauth_nonce="2294192392"
, oauth_version="1.0"
, oauth_token="yyyyyyyyyyyyyyyyyyyyyyyyyyy"
, oauth_verifier="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
, oauth_signature="vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
Content-Type: application/x-www-form-urlencoded
Host: api.twitter.com
Content-Length: 0
Connection: Keep-Alive
RESPONSE
HTTP/1.1 401 Authorization Required
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
content-length: 136
content-security-policy: default-src https:; connect-src https:; font-src https: data:; frame-src https:; img-src https: data:; media-src https:; object-src https:; script-src 'unsafe-inline' 'unsafe-eval' https:; style-src 'unsafe-inline' https:; report-uri https://twitter.com/i/csp_report?a=NVXW433SMFUWY%3D%3D%3D&ro=false;
content-type: text/html; charset=utf-8
date: Wed, 26 Nov 2014 16:23:13 UTC
expires: Tue, 31 Mar 1981 05:00:00 GMT
last-modified: Wed, 26 Nov 2014 16:23:13 GMT
pragma: no-cache
server: tsa_b
set-cookie: _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCEzs6exJAToHaWQiJWI5MDgzMzk0Y2FhMGY2%250AMGNlNmEyYzQzZjk5OGEyNjAyIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--86562a75e3ddabab3c688e726e6c42fe37a067ea; domain=.twitter.com; path=/; secure; HttpOnly
set-cookie: guest_id=v1%3A141701899357688419; Domain=.twitter.com; Path=/; Expires=Fri, 25-Nov-2016 16:23:13 UTC
status: 401 Unauthorized
strict-transport-security: max-age=631138519
vary: Accept-Encoding
www-authenticate: OAuth realm="https://api.twitter.com"
x-connection-hash: 24d849ec3bead25133b581794d34c74f
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-mid: aed281dc4b2e3fb483737ccd772ce1d8d3f6064d
x-transaction: d41ff14981c7a0ec
x-ua-compatible: IE=edge,chrome=1
x-xss-protection: 1; mode=block
<?xml version="1.0" encoding="UTF-8"?>
<hash>
<error>Invalid / expired Token</error>
<request>/oauth/access_token</request>
</hash>
Can anyone help or advice on what I should be persisting to be able to post on behalf of a user - once they've given us permission from a service or console application.
Thanks in advance.
I managed to solve issue. I removed Spring.Social from equation and wrote some quick code to talk to Twitter API without a framework, this gave me a better understanding of what the steps and process were.
Using this I then re-added the framework and I think I use it correctly now. As it all works.
My issue was that once I got my request token+verifier - supplying callback, consumer etc. I then used that to get an access token to perform posts etc.
However, every time I attempted to post I tried to exchange request token value + secret and verifier to get the access token. This eventually fails.
I changed code to save returned access token and just use that directly, works fine now.
This is a strange one. I'm running MVC 3 and have a custom action result that wraps exceptions and returns a message along with the standard HTTP error.
public class ExceptionResult : ActionResult
{
private readonly Exception _exception;
public ExceptionResult(Exception exception)
{
_exception = exception;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ClearHeaders();
response.Cache.SetNoStore();
response.ContentType = ContentType.Json;
var baseEx = _exception as BaseException ?? new ServerException(_exception);
var result = baseEx.GetResult();
var json = result.ToJSON();
response.Write(json);
response.StatusCode = (int)result.Status.Code;
}
}
When I run this locally I get exactly what I expect:
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Date: Thu, 01 Dec 2011 19:00:03 GMT
Content-Length: 81
{"error":"invalid_request","error_description":"Parameter grant_type is missing"}
But when I try to connect from a different machine I get the standard IIS error message instead:
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Date: Thu, 01 Dec 2011 19:02:33 GMT
Content-Length: 11
Bad Request
UPDATE
There must be some http module somewhere in the IIS pipeline that is swallowing the response and rewriting the content. I wrote a module to log the request and response and it's returning exactly what I expect however what actually makes it to the browser is wrong.
2011-12-02 15:39:00,518 - ======== Request ========
2011-12-02 15:39:00,518 - GET /oauth/2/token HTTP/1.1
2011-12-02 15:39:00,519 - Cache-Control: max-age=0
2011-12-02 15:39:00,519 - Connection: keep-alive
2011-12-02 15:39:00,519 - Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
2011-12-02 15:39:00,519 - Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
2011-12-02 15:39:00,519 - Accept-Encoding: gzip,deflate,sdch
2011-12-02 15:39:00,519 - Accept-Language: en-US,en;q=0.8
2011-12-02 15:39:00,519 - Host: micah-pc:8095
2011-12-02 15:39:00,519 - User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2
2011-12-02 15:39:00,519 - =========================
2011-12-02 15:39:00,519 - OAuth exception occurred.
BoomTown.OAuth.OAuthException: Parameter grant_type is missing
at BoomTown.OAuth.Request.TokenRequest.GetRequestValidator() in C:\code\BoomTown\Api\BoomTown.OAuth\Request\TokenRequest.cs:line 19
at BoomTown.OAuth.Request.OAuthRequestBase.Validate() in C:\code\BoomTown\Api\BoomTown.OAuth\Request\OAuthRequestBase.cs:line 33
at BoomTown.OAuth.Request.OAuthRequestBase..ctor(HttpRequestBase request, IOAuthServiceLocator serviceLocator) in C:\code\BoomTown\Api\BoomTown.OAuth\Request\OAuthRequestBase.cs:line 28
at BoomTown.OAuth.Request.TokenRequest..ctor(HttpRequestBase request, IOAuthServiceLocator serviceLocator) in C:\code\BoomTown\Api\BoomTown.OAuth\Request\TokenRequest.cs:line 13
at BoomTown.Api.Web.Controllers.OAuth.V2.OAuthController.Token() in C:\code\BoomTown\Api\BoomTown.Api.Web\Controllers\OAuth\V2\OAuthController.cs:line 26
2011-12-02 15:39:00,520 - ======= Response =======
2011-12-02 15:39:00,520 - HTTP/1.1 400 Bad Request
2011-12-02 15:39:00,520 - Cache-Control: no-store
2011-12-02 15:39:00,520 - X-AspNet-Version: 4.0.30319
2011-12-02 15:39:00,520 - Content-Type: application/json; charset=utf-8
2011-12-02 15:39:00,520 - {"error":"invalid_request","error_description":"Parameter grant_type is missing"}
SOLUTION
Thanks to a little sleuthing I was able to figure it out. I setup IIS tracing which confirmed my suspicions that it was related to the customerrormodule which was intercepting my requests and overwriting my error messages. I kept monkeying with the
<system.web>
<customErrors />
<system.web>
settings but to no avail. I was on the right track, but since it's IIS 7 that I'm running I needed to change the correct web.config section like this:
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
Now all my custom JSON messages come through perfectly. Big thanks to Jason Finneyfrock for the tag team on this one.
In your web.config, do you have httpErrors defined to only be DetailedLocalOnly? I'm not sure whether or not the content would be removed in this situation.
http://www.iis.net/ConfigReference/system.webServer/httpErrors
I came across this, not sure if it will help:
context.HttpContext.Response.TrySkipIisCustomErrors = true;