create certificateRequest from base64 string in .net Framework 4.7.2 - c#

In the past I used for our certTool the com CERTENROLLLib to create the csr. Since Version 4.7.2 you can use the .net Framework.
It is possible to create the csr by passing all the necessary Attributes in the CreateSigningRequest Method and convert it into a pem base64 string.
Unfortunately I couldn't find the other way around, copy a csr in pem Format in a field and read all the csr Attributes from it (cn, san, organization, etc.)
I don't want to use the com lib CERTENROLLLib, openssl or other 3rd parties.
Here is what I have done (to get the csr pem string) found good examples in here and at MS Framework class description, thanks for your help
protected void createButton_Click(object sender, EventArgs e)
{
string csr_cn = txtb_csr_cn.Text;
string csr_c = txtb_csr_c.Text;
string csr_l = txtb_csr_l.Text;
string csr_o = txtb_csr_o.Text;
string csr_ou = txtb_csr_ou.Text;
string csr_s = txtb_csr_s.Text;
csr_san = sanMemo.Text.Replace(" ", "");
if (csr_san.IndexOf(csr_cn) == -1)
{
if (csr_san == "")
{
csr_san = csr_cn;
}
else
{
csr_san = csr_cn + "," + csr_san;
}
}
csr_key_size = Convert.ToInt32(combobox_csr_key.Text);
csr_info = "CN=" + csr_cn + "," + "OU=" + csr_ou + "," + "O=" + csr_o + "," + "L=" + csr_l + "," + "S=" + csr_s + "," + "C=" + csr_c;
notesMemo.Text = CreateCSR(); //CreateRequest();
}
public static string CreateCSR()
{
string[] arrSeperator = new string[] { "," };
RSA keySize = RSA.Create(csr_key_size);
CertificateRequest parentReq = new CertificateRequest(csr_info,
//"CN=Experimental Issuing Authority",
keySize,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
parentReq.CertificateExtensions.Add(
new X509BasicConstraintsExtension(true, false, 0, true));
parentReq.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(parentReq.PublicKey, false));
var sanBuilder = new SubjectAlternativeNameBuilder();
Array arrsan = csr_san.Split(arrSeperator, StringSplitOptions.RemoveEmptyEntries);
foreach (string sanvalue in arrsan)
{
sanBuilder.AddDnsName(sanvalue);
}
parentReq.CertificateExtensions.Add(sanBuilder.Build());
string csrdecrypt = PemEncodeSigningRequest(parentReq);
return csrdecrypt;
}
public static string PemEncodeSigningRequest(CertificateRequest request)
{
byte[] pkcs10 = request.CreateSigningRequest();
StringBuilder builder = new StringBuilder();
builder.AppendLine("-----BEGIN CERTIFICATE REQUEST-----");
string base64 = Convert.ToBase64String(pkcs10);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.AppendLine("-----END CERTIFICATE REQUEST-----");
string tester2 = builder.ToString();
return builder.ToString();
}

There is no pure-managed way to read a Certification Signing Request without third party libraries.
You could try using a P/Invoke to CryptDecodeObjectEx, possibly using the structure identifier of X509_CERT (per https://learn.microsoft.com/en-us/windows/desktop/SecCrypto/constants-for-cryptencodeobject-and-cryptdecodeobject).
But the CertificateRequest class is a PKCS#10 writer without a reader in .NET Framework.
Update (2023-01-30): LoadSigningRequestPem and friends were added in .NET 7.

Related

GoogleSmarthome JWT Creation

The documentation is at Using OAuth 2.0 for Server to Server Applications
You will notice in the documentation the disclaimer "don't do this but use the libraries". Unfortunately, there does NOT appear to be .Net Core libraries and I have suggested to the Smarthome program managers that support for .Net Core should be the same as provided for Java, node.js and Python.
However, I'm hunkered down, socially distanced and have some time available so I gave it a shot. There are a lot of moving parts here but to start I downloaded a p12 file instead of a JSON file (as indicated in the documentation) from the Google Console for the account.
The code:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace MakeJWTTest
{
class Program
{
static void Main(string[] args)
{
string token = MakeJwt();
Console.WriteLine();
Console.WriteLine("The Final JWT: " + token );
}
public static string MakeJwt()
{
string jwt = string.Empty;
string iss = "XXXXXXXXXXXXXXX-v2.iam.gserviceaccount.com";
string scope = "https://www.googleapis.com/auth/homegraph";
string aud = "https://oauth2.googleapis.com/token";
string exp = EpochExpiration();
string iat = EpochCurrentTime();
string jwtHeader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
Console.WriteLine("iss: " + iss);
Console.WriteLine("scope: " + scope);
Console.WriteLine("aud: " + aud);
Console.WriteLine("exp: " + exp);
Console.WriteLine("iat: " + iat);
Console.WriteLine("JWT Header: " + jwtHeader);
string claim = "{\"iss\": \"" + iss + "\",\"scope\": \"" + scope + "\",\"aud\": \"" + aud + "\",\"exp\": " +
exp + ",\"iat\": " + iat + "}";
var encodedHeader = Base64UrlEncoder.Encode(jwtHeader);
Console.WriteLine("Encoded JWT Header: " + encodedHeader);
var encodedClaim = Base64UrlEncoder.Encode(claim);
string claimSet = encodedHeader + "." + encodedClaim;
string sig = Sign(claimSet);
jwt = claimSet + '.' + sig;
return jwt;
}
public static string EpochExpiration()
{
DateTime epoch = DateTime.UnixEpoch;
DateTime now = DateTime.UtcNow;
DateTime expiration = now.AddMinutes(60);
TimeSpan secondsSinceEpoch = expiration.Subtract(epoch);
return secondsSinceEpoch.TotalSeconds.ToString().Substring(0, 10);
}
public static string EpochCurrentTime()
{
DateTime epoch = DateTime.UnixEpoch;
DateTime now = DateTime.UtcNow;
TimeSpan secondsSinceEpoch = now.Subtract(epoch);
return secondsSinceEpoch.TotalSeconds.ToString().Substring(0, 10);
}
public static string Sign( string toSHA256)
{
try
{
byte[] data = Encoding.ASCII.GetBytes(toSHA256);
var certificate = new X509Certificate2(#"XXXXXXXXXXXXXXX-v2-6790af22aa27.p12", "notasecret", X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
// byte[] key = certificate.PrivateKey.ExportPkcs8PrivateKey();
key.FromXmlString(certificate.PrivateKey.ToXmlString(true));
//Sign the data
byte[] sig = key.SignData(data, CryptoConfig.MapNameToOID("SHA256"));
return Base64UrlEncoder.Encode(sig);
}
catch { Exception e; return null; }
}
}
}
Run this program and I get:
scope: https://www.googleapis.com/auth/homegraph
aud: https://oauth2.googleapis.com/token
exp: 1586193162
iat: 1586189562
JWT Header: {"alg":"RS256","typ":"JWT"}
Encoded JWT Header: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
The Final JWT: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiAibGltaXRlZG1vYmlsaXR5djJAbGltaXRlZC1tb2JpbGl0eS1zb2x1dGlvbnMtdjIuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iICJzY29wZSI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2hvbWVncmFwaCJhdWQiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20vdG9rZW4iZXhwIjogIjE1ODYxOTMxNjIiaWF0IjogMTU4NjE4OTU2Mg.ZOX93iUhirtH2tf95XzLYrGIbTK8kABipfVa6DnD-sAe3WcRfLmLVIAybtHTHxC8frCuZtCeS4XMT-EC69kLy-ks5BWFTnaRwm0TfIeNzIVrGfJUVRchvaJLFM9-wX6svVa4fGHMp8pKttO22BI3sIEisxXx2tw6Ge_8QRZXjSCXD0rg5P-0S-pnd8omkgPv_PhhALqcwd9RTUpcAqcMDoyP7ZxpBSMt1EwySixctKz2y4sRCGC8xaxp5E5VnH3liz3xTNMY5QRNX-tMxVIunh0Qp9v7bkuuvnhrwbcjRPq9qTKlhfIQBmZvaA5-9hzJZOiWWHmCunMec1pZp0bAgQ
Press any key to close this window . . .
I then run this from Powershell using curl:
.\curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU' https://oauth2.googleapis.com/token
Which returns:
{"error":"invalid_grant","error_description":"Invalid grant: account not found"}
Could be a bunch of things wrong here. Any thoughts welcomed.
There were two errors in the code:
The JSON string
claim = "{\"iss\": \"" + iss + "\",\"scope\": \"" + scope +
"\",\"aud\": \"" + aud + "\",\"exp\": " +
exp + ",\"iat\": " + iat + "}";
The DateTime needs to be UTC
And now it works.

401 Error when trying to get Request Token

resp = (HttpWebResponse)request.GetResponse();Right I know this is probably some stupid mistake or just me not being well versed in Oauth stuff but I have come to a grinding halt and have no idea where to go from here, after many searches and attempts I humbly ask for some help.
I am attempting to get a request token from Twitter to try and get a users twitter feeds, I cannot use a library for other business reasons...
Here is the code so far:
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("oauth_callback", "www.url.com/redirect.aspx");
parameters.Add("oauth_consumer_key", <Consumer_KEY>);
parameters.Add("oauth_nonce", generateNonce());
parameters.Add("oauth_signature_method", "HMAC-SHA1");
parameters.Add("oauth_timestamp", CurrentUNIXTimestamp.Get());
parameters.Add("oauth_version", "1.0");
parameters = parameters.OrderBy(x => x.Key).ToDictionary(v => v.Key, v => v.Value);
string concat = "";
string OAuthHeader = "OAuth ";
foreach (string k in parameters.Keys)
{
if (k == "oauth_callback")
{
concat += k + "%3D" + EncodeToUpper(parameters[k]) + "%26";
OAuthHeader += k + "=" + "\"" + EncodeToUpper(parameters[k]) + "\", ";
}
else
{
concat += k + "%3D" + parameters[k] + "%26";
OAuthHeader += k + "=" + "\"" + parameters[k] + "\", ";
}
}
concat = concat.Remove(concat.Length - 3, 3);
concat = "POST&" + EncodeToUpper("https://api.twitter.com/oauth/request_token" ) + "&" + concat;
//byte[] content = Encoding.UTF8.GetBytes(concat);
HMACSHA1 hmacsha1 = new HMACSHA1();
hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", EncodeToUpper(<CONSUMER SECRET>, ""));
byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(concat);
byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
string hash = Convert.ToBase64String(hashBytes);
OAuthHeader += "oauth_signature=\"" + EncodeToUpper(hash) + "\"";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.twitter.com/oauth/request_token");
request.Method = "POST";
request.Headers["Authorization"] = OAuthHeader;
StringBuilder responding = new StringBuilder();
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)request.GetResponse();
}
catch (WebException exc)
{
lblError.Text = "Error Connecting to Social Network " + exc.Message;
}
if (resp != null)
{
using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
{
responding.Append(reader.ReadToEnd());
}
}
An Example of the Nonce is "ne8ehvVr0pW2EUxNHdxdyqbi8Fwphatt3SW1yerTyXH" and the CurrentUNIXTimestamp is generated by
public static class CurrentUNIXTimestamp
{
public static string Get()
{
return Convert.ToString((int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);
}
}
I have tried as many things as I can think of, there is no longer a client/browser issue (which was many other answers), the server time is correct to British Summer Time (I don't know whether that would be an issue but I tried adding an hour to the unix time stamp still a 401.), and i have defined the callback url on the twitter app page
I have got the same app working with facebook (I know its different oauth but may help)
The actual error comes at resp = (HttpWebResponse)request.GetResponse();, which comes up with a 401 error. I couldn't get any further details from the exc.response object, could anyone say how to get something useful out of the error in VS2008?
Thanks for any answers
The hardest problem I had implementing OAuth was dealing with character encoding. It's very particular.
Here is the code I ended up writing for it.
private static string UrlEncode(IEnumerable<KeyValuePair<string, object>> parameters)
{
StringBuilder parameterString = new StringBuilder();
var paramsSorted = from p in parameters
orderby p.Key, p.Value
select p;
foreach (var item in paramsSorted)
{
if (parameterString.Length > 0)
{
parameterString.Append("&");
}
if(item.Value.GetType() == typeof(string) )
parameterString.Append(
string.Format(
CultureInfo.InvariantCulture,
"{0}={1}",
UrlEncode(item.Key),
UrlEncode(item.Value as string)));
}
return UrlEncode(parameterString.ToString());
}
public static string UrlEncode(string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
value = Uri.EscapeDataString(value);
// UrlEncode escapes with lowercase characters (e.g. %2f) but oAuth needs %2F
value = Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
// these characters are not escaped by UrlEncode() but needed to be escaped
value = value
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("$", "%24")
.Replace("!", "%21")
.Replace("*", "%2A")
.Replace("'", "%27");
// these characters are escaped by UrlEncode() but will fail if unescaped!
value = value.Replace("%7E", "~");
return value;
}
If you really get fed up, you can use the WebRequestBuilder class from my library to do all the OAuth stuff for you: http://www.twitterizer.net/

EWS + Exchange 2007: Retrieve inline images

Working in C# with the EWS Managed API, we're having trouble efficiently retrieving the images stored as inline attachments.
The endpoint is to show an email with inline images as a fully formed html page in a panel. The code we currently us:
string sHTMLCOntent = item.Body;
FileAttachment[] attachments = null;
if (item.Attachments.Count != 0)
{
attachments = new FileAttachment[item.Attachments.Count];
for (int i = 0; i < item.Attachments.Count; i++)
{
string sType = item.Attachments[i].ContentType.ToLower();
if (sType.Contains("image"))
{
attachments[i] = (FileAttachment)item.Attachments[i];
string sID = attachments[i].ContentId;
sType = sType.Replace("image/", "");
string sFilename = sID + "." + sType;
string sPathPlusFilename = Directory.GetCurrentDirectory() + "\\" + sFilename;
attachments[i].Load(sFilename);
string oldString = "cid:" + sID;
sHTMLCOntent = sHTMLCOntent.Replace(oldString, sPathPlusFilename);
}
}
}
(sourced: http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/ad10283a-ea04-4b15-b20a-40cbd9c95b57)
.. this is not very efficient though and is slowing down the responsiveness of our web app. Does anyone have a better solution for this problem? We are using Exchange 2007 SP1, so the IsInline property wont work as its Exchange 2010 only.
I build an index of your "cid:"s first:
private const string CidPattern = "cid:";
private static HashSet<int> BuildCidIndex(string html)
{
var index = new HashSet<int>();
var pos = html.IndexOf(CidPattern, 0);
while (pos > 0)
{
var start = pos + CidPattern.Length;
index.Add(start);
pos = html.IndexOf(CidPattern, start);
}
return index;
}
Then you need a replace function that replaces the cids based on your index
private static void AdjustIndex(HashSet<int> index, int oldPos, int byHowMuch)
{
var oldIndex = new List<int>(index);
index.Clear();
foreach (var pos in oldIndex)
{
if (pos < oldPos)
index.Add(pos);
else
index.Add(pos + byHowMuch);
}
}
private static bool ReplaceCid(HashSet<int> index, ref string html, string cid, string path)
{
var posToRemove = -1;
foreach (var pos in index)
{
if (pos + cid.Length < html.Length && html.Substring(pos, cid.Length) == cid)
{
var sb = new StringBuilder();
sb.Append(html.Substring(0, pos-CidPattern.Length));
sb.Append(path);
sb.Append(html.Substring(pos + cid.Length));
html = sb.ToString();
posToRemove = pos;
break;
}
}
if (posToRemove < 0)
return false;
index.Remove(posToRemove);
AdjustIndex(index, posToRemove, path.Length - (CidPattern.Length + cid.Length));
return true;
}
so now, you can check your attachments
FileAttachment[] attachments = null;
var index = BuildCidIndex(sHTMLCOntent);
if (index.Count > 0 && item.Attachments.Count > 0)
{
var basePath = Directory.GetCurrentDirectory();
attachments = new FileAttachment[item.Attachments.Count];
for (var i = 0; i < item.Attachments.Count; ++i)
{
var type = item.Attachments[i].ContentType.ToLower();
if (!type.StartsWith("image/")) continue;
type = type.Replace("image/", "");
var attachment = (FileAttachment)item.Attachments[i];
var cid = attachment.ContentId;
var filename = cid + "." + type;
var path = Path.Combine(basePath, filename);
if(ReplaceCid(index, ref sHTMLCOntent, cid, path))
{
// only load images when they have been found
attachment.Load(path);
attachments[i] = attachment;
}
}
}
Additional to that: instead of calling attachment.Load right away, and pass the path to the image directly, you could link to another script, where you pass the cid as a parameter and then check back with the exchange for that image; then the process of loading the image from exchange does not block the html cid replacement and could lead to loading the page faster, since the html can send to the browser sooner.
PS: Code is not tested, just so you get the idea!
EDIT
Added the missing AdjustIndex function.
EDIT 2
Fixed small bug in AdjustIndex

Store sensitive information inside keepass database from c#

I have a project where I have to handle sensitive data.
How do I open a keepass database from C# to use the data?
I have downloaded the source. I will look in it to get what I need. Any other idea?
I thought about reading a KeyPass 2 database so I added a reference to KeyPass.exe in Linqpad and started to experiment. To my surprise and without any outside help (a testament to a good API), I was reading the database after only a few minutes. Here's how I did it:
var dbpath = #"C:\path\to\passwords.kdbx";
var masterpw = "Your$uper$tr0ngMst3rP#ssw0rd";
var ioConnInfo = new IOConnectionInfo { Path = dbpath };
var compKey = new CompositeKey();
compKey.AddUserKey(new KcpPassword(masterpw));
var db = new KeePassLib.PwDatabase();
db.Open(ioConnInfo, compKey, null);
var kpdata = from entry in db.RootGroup.GetEntries(true)
select new
{
Group = entry.ParentGroup.Name,
Title = entry.Strings.ReadSafe("Title"),
Username = entry.Strings.ReadSafe("UserName"),
Password = entry.Strings.ReadSafe("Password"),
URL = entry.Strings.ReadSafe("URL"),
Notes = entry.Strings.ReadSafe("Notes")
};
kpdata.Dump(); // this is how Linqpad outputs stuff
db.Close();
Here is an extension of the original answer from Ronnie - walking the keepass tree recursively. This outputs a format that jsTree can use by the way.
public static void JsonData() {
var dbpath = Web.MapPath(#"your-password-file.kdbx");
var masterpw = "Your$uper$tr0ngMst3rP#ssw0rd";
var ioConnInfo = new IOConnectionInfo { Path = dbpath };
var compKey = new CompositeKey();
compKey.AddUserKey(new KcpPassword(masterpw));
var db = new KeePassLib.PwDatabase();
db.Open(ioConnInfo, compKey, null);
//get everything
var kpdata = from entry in db.RootGroup.GetEntries(true)
select new {
Group = entry.ParentGroup.Name,
Title = entry.Strings.ReadSafe("Title"),
Username = entry.Strings.ReadSafe("UserName"),
Password = entry.Strings.ReadSafe("Password"),
URL = entry.Strings.ReadSafe("URL"),
Notes = entry.Strings.ReadSafe("Notes")
};
var kproot = db.RootGroup.Groups;
string lastGroup = "#";
uint sc = 0;
int depth = 0;
var parent = "#"; //root is # parent
foreach (var entry in kproot) {
PwGroup pwGroup = db.RootGroup.Groups.GetAt(sc);
Web.Write(" { \"id\" : \"" + (sc) + "\", \"parent\" : \"" + parent + "\", \"text\" : \"" + pwGroup.Name.HtmlEncode() + "\" },\n");
WriteChildren(pwGroup,sc+"", depth + 1);
sc++;
}
db.Close();
}
public static void WriteChildren(PwGroup pwGroup, string parentID,int depth) {
uint sc = 0;
//if(depth>3)return; //used to prevent too much recursion
foreach (var entry in pwGroup.Groups) {
var subGroup = pwGroup.Groups.GetAt(sc);
var curID = (parentID+"_"+sc);
Web.Write(" { \"id\" : \"" + curID + "\", \"parent\" : \"" + parentID + "\", \"text\" : \"" + subGroup.Name.JsEncode() + "\"},\n");
WriteChildren(subGroup, curID, depth+1);
WriteLeaves(subGroup, curID, depth);
sc++;
}
}
public static void WriteLeaves(PwGroup pwGroup, string parentID,int depth) {
uint sc = 0;
//if(depth>3)return;
var entryList = pwGroup.GetEntries(false);
foreach (var entry in entryList) {
var curID = (parentID+"_"+sc);
Web.Write(" { \"id\" : \"" + curID + "\", \"parent\" : \"" + parentID + "\", \"text\" : \"" + entry.Strings.ReadSafe("Title").JsEncode() + "\", \"password\" : \"" + entry.Strings.ReadSafe("Password").JsEncode() + "\", \"type\" : \"file\"},\n");
sc++;
}
}
Check : KeePass Password Safe (For how keepass works)
Rather use the C# System.Cryptography classes and store you data enrypted in a database or txt file...
There is a KeePass-2.05-Alpha-Source.zip,The latest version of KeePass. C# source code,1919KB
http://s.pudn.com/upload_log_en.asp?e=1781366
http://en.pudn.com/downloads175/sourcecode/windows/other/detail816102_en.html

Google OAuth from Windows Phone invalid signature

I've spent the past couple nights on this, and it's driving me mad. Hopefully someone can shed some light on this.
I'm trying to write a Windows Phone 7 app to connect to Google. The OAuth routine is really giving me trouble.
I've seen quite a few twitter examples, but nothing specific to Google. The code is below - every time I make the request, Google says 'invalid signature.' The base URLs match, everything seems kosher - but it refuses to take it.
string baseReqUrl = "https://www.google.com/accounts/OAuthGetRequestToken";
string oauth_consumer_key = "CONSUMER_KEY";
string oauth_consumer_secret = "CONSUMER_SECRET";
string oauth_nonce = OAuthLibrary.OAuth.CreateNonce();
string oauth_signature_method = "HMAC-SHA1";
long oauth_timestamp = OAuthLibrary.OAuth.CreateTimestamp();
//string scope = "https%3A%2F%2Fwww.google.com%2Fanalytics%2Ffeeds%2F";
string scope = "https://www.google.com/analytics/feeds/";
string oauth_callback = "oob";
List<string> sig = new List<string>();
sig.Add(baseReqUrl);
sig.Add("oauth_callback=" + oauth_callback);
sig.Add("oauth_conusmer_key=" + oauth_consumer_key);
sig.Add("oauth_nonce=" + oauth_nonce);
sig.Add("oauth_signature_method=" + oauth_signature_method);
sig.Add("oauth_timestamp=" + oauth_timestamp.ToString());
sig.Add("scope=" + scope);
string baseReq = "GET";
int i = 0;
foreach (string s in sig)
{
if (i == 1)
{
baseReq = baseReq + "?" + s;
}
else
{
baseReq = baseReq + "&" + s;
}
i++;
}
HMACSHA1 h = new HMACSHA1(Encoding.UTF8.GetBytes(oauth_consumer_secret));
OAuth.OAuthBase b = new OAuth.OAuthBase();
string normalizedUrl = string.Empty;
string normalizedRequestParameters = string.Empty;
string sigBase = b.GenerateSignatureBase(new Uri(baseReq.Substring(4)), oauth_consumer_key, null, null, "GET", oauth_timestamp.ToString(), oauth_nonce, "HMAC-SHA1", out normalizedUrl, out normalizedRequestParameters);
string signature = b.GenerateSignatureUsingHash(sigBase, h);
string reqUrl = normalizedUrl + "?" + normalizedRequestParameters + "&oauth_signature=" + signature;
GetUrl(reqUrl); //this line just makes the request

Categories

Resources