Google Apps Marketplace UpgradeableApp API Getting "code":500,"message":"Backend Error" - oauth

We are in process of migration of Google Apps Marketplace listing using the UpgradeableApp API resource but when calling
PUT https://www.googleapis.com/appsmarket/v2/upgradableApp/listingID/cwsID/domain
with signed request getting error:
81 {"error":{"errors":[{"domain":"global","reason":"backendError","message":"Backend Error"}],"code":500,"message":"Backend Error"}} 0
What i am doing wrong....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OAuth.Net.Common;
using OAuth.Net.Components;
using System.IO;
using System.Net;
using System.Security.Cryptography;
namespace Google_UpgradeableApi_Console
{
class Program
{
private static readonly ISigningProvider SigningProvider = new HmacSha1SigningProvider();
static void Main(string[] args)
{
// Setup the variables necessary to create the OAuth 1.0 signature and make the request
string httpMethod = "PUT";
string listingID = "xxxx+23453809800066606066";
string cwsID = "bbmagicjcjeblpadhhnnjahfbbbbhjk";
string domain = "xyz.com";
Uri url = new Uri(String.Format("{0}/{1}/{2}/{3}", "https://www.googleapis.com/appsmarket/v2/upgradableApp", listingID, cwsID, domain));
string consumerKey = "xyz.apps.googleusercontent.com";
string secret = "gt2sj34656U687f8qj677+GK";
string body = "";
MemoryStream requestBody = null;
string signatureMethod = SigningProvider.SignatureMethod;
HttpWebResponse response = null;
// Set the Nonce and Timestamp parameters
string nonce = getNonce();
string timestamp = getTimestamp();
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
requestBody = new MemoryStream(Encoding.UTF8.GetBytes(body));
}
// Create the OAuth parameter name/value pair dictionary
Dictionary<string, string> oauthParams = new Dictionary<string, string>
{
{ "oauth_consumer_key", consumerKey },
{ "oauth_signature_method", signatureMethod },
{ "oauth_timestamp", timestamp },
{ "oauth_nonce", nonce },
};
// Get the OAuth 1.0 Signature
string signature = generateSignature(httpMethod, url, oauthParams, requestBody, secret);
Console.WriteLine("OAuth 1.0 Signature = " + signature + "\r\n\r\n");
// Add the oauth_signature parameter to the set of OAuth Parameters
IEnumerable<KeyValuePair<string, string>> allParams = oauthParams.Union(new[]
{
new KeyValuePair<string, string>("oauth_signature", signature)
});
// Defines a query that produces a set of: keyname="URL-encoded(value)"
IEnumerable<string> encodedParams = from param in allParams
select param.Key + "=\"" + Uri.EscapeDataString(param.Value) + "\"";
// Join all encoded parameters with a comma delimiter and convert to a string
string stringParams = String.Join(",", encodedParams);
// Build the X-Authorization request header
string xauth = String.Format("X-Authorization: OAuth realm=\"{0}\",{1}", url, stringParams);
Console.WriteLine("X-Authorization request header: \r\n" + xauth + "\r\n\r\n");
try
{
// Setup the Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = httpMethod;
request.Headers.Add(xauth);
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
byte[] dataArray = Encoding.UTF8.GetBytes(body);
request.ContentLength = dataArray.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(dataArray, 0, dataArray.Length);
requestStream.Close();
}
// Send Request & Get Response
response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// Get the response stream and write to console
string json = reader.ReadToEnd();
Console.WriteLine("Successful Response: \r\n" + json);
}
}
catch (WebException e)
{
// This exception will be raised if the server didn't return 200 - OK
// Retrieve more information about the error
if (e.Response != null)
{
using (HttpWebResponse err = (HttpWebResponse)e.Response)
{
Console.WriteLine("The server returned '{0}' with the status code '{1} ({2:d})'.",
err.StatusDescription, err.StatusCode, err.StatusCode);
}
}
}
finally
{
if (response != null) { response.Close(); }
}
Console.ReadLine();
}
#region Helper Functions
/// <summary>
/// Generates a random nonce.
/// </summary>
/// <returns>A unique identifier for the request.</returns>
private static string getNonce()
{
string rtn = Path.GetRandomFileName() + Path.GetRandomFileName() + Path.GetRandomFileName();
rtn = rtn.Replace(".", "");
if (rtn.Length > 32)
return rtn.Substring(0, 32);
else
return rtn;
}
/// <summary>
/// Generates an integer representing the number of seconds since the unix epoch using the
/// UTC date/time of the request.
/// </summary>
/// <returns>A timestamp for the request.</returns>
private static string getTimestamp()
{
return ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
}
/// <summary>
/// Generates an OAuth 1.0 signature.
/// </summary>
/// <param name="httpMethod">The HTTP method of the request.</param>
/// <param name="url">The URI of the request.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <param name="secret">Alphanumeric string used to validate the identity of the education partner (Private Key).</param>
/// <returns>A string containing the BASE64-encoded signature digest.</returns>
private static string generateSignature(
string httpMethod,
Uri url,
IDictionary<string, string> oauthParams,
Stream requestBody,
string secret
)
{
// Ensure the HTTP Method is upper-cased
httpMethod = httpMethod.ToUpper();
// Construct the URL-encoded OAuth parameter portion of the signature base string
string encodedParams = normalizeParams(httpMethod, url, oauthParams, requestBody);
// URL-encode the relative URL
string encodedUri = Uri.EscapeDataString(url.AbsolutePath);
// Build the signature base string to be signed with the Consumer Secret
string baseString = String.Format("{0}&{1}&{2}", httpMethod, encodedUri, encodedParams);
//return generateCmac(secret, baseString);
return generateHMAC(secret, baseString);
}
/// <summary>
/// Normalizes all oauth signable parameters and url query parameters according to OAuth 1.0.
/// </summary>
/// <param name="httpMethod">The upper-cased HTTP method.</param>
/// <param name="url">The request URL.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <returns>A string containing normalized and encoded OAuth parameters.</returns>
private static string normalizeParams(
string httpMethod,
Uri url,
IEnumerable<KeyValuePair<string, string>> oauthParams,
Stream requestBody
)
{
IEnumerable<KeyValuePair<string, string>> kvpParams = oauthParams;
// Place any Query String parameters into a key value pair using equals ("=") to mark
// the key/value relationship and join each paramter with an ampersand ("&")
if (!String.IsNullOrWhiteSpace(url.Query))
{
IEnumerable<KeyValuePair<string, string>> queryParams =
from p in url.Query.Substring(1).Split('&').AsEnumerable()
let key = Uri.EscapeDataString(p.Substring(0, p.IndexOf("=")))
let value = Uri.EscapeDataString(p.Substring(p.IndexOf("=") + 1))
select new KeyValuePair<string, string>(key, value);
kvpParams = kvpParams.Union(queryParams);
}
// Include the body parameter if dealing with a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
MemoryStream ms = new MemoryStream();
requestBody.CopyTo(ms);
byte[] bodyBytes = ms.ToArray();
string body = Convert.ToBase64String(bodyBytes, Base64FormattingOptions.None);
body = Uri.EscapeDataString(body);
kvpParams = kvpParams.Union(new[]
{
new KeyValuePair<string, string>("body", Uri.EscapeDataString(body))
});
}
// Sort the parameters in lexicographical order, 1st by Key then by Value; separate with ("=")
IEnumerable<string> sortedParams =
from p in kvpParams
orderby p.Key ascending, p.Value ascending
select p.Key + "=" + p.Value;
// Add the ampersand delimiter and then URL-encode the equals ("%3D") and ampersand ("%26")
string stringParams = String.Join("&", sortedParams);
string encodedParams = Uri.EscapeDataString(stringParams);
return encodedParams;
}
private static string generateHMAC(string _key, string _msg)
{
string message;
string key;
key = _key;
message = _msg;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA1 hmacsha1 = new HMACSHA1(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
return ByteToString(hashmessage);
}
public static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
#endregion // Helper Functions
}
}

There are many reasons behind this, but first please check the URL must be signed with OAuth1 (not OAuth2) and must have valid values for the other parameters. The error reporting may make throw the same error for a lot of reason, but make sure your setup is correct and make sure your app is published on new chrome apps marketplace. Make sure you've submitted the Google Apps Marketplace Listing Review Request form here:
https://docs.google.com/forms/d/14QOb8PbSLKDgwIp8Zv-luoAAVurPXUqtzL0Hgikp3rk/viewform
After all is finished and google approved (you will get an email) your app then make call to UpgradeableApp API with oAuth 1.0 sign request, Here is an example you can see how to do it.
http://www.codeproject.com/Tips/359144/Legged-OAuth-Authentication-in-NET-Csharp
Hope that helps

Related

Docusign Embedded Signing(MVC website) - tags not showing up and the document is coming as free form signing

I am trying to integrate my website with Docusign via embedded signing. I have been pretty successful - thanks to the documentation and pointers from SO).
My issue is that I have a website and on initial sign up I need the users to e-sign a document before they proceed to shop at my site. So I have set up a docusign embedded signing experience once they login - which will take them seamlessly(without login to docusign server etc) to Docusign - where in the document for signing shows up - this document is coming thru fine - but the tags are not showing up and it is showing as free form signing. There are "FIELDS" to the left of my document and I need to drag and drop these on the form ( I have populated these fields with values).
The real issue is docusign lets me "FINISH" without signing since the document is showing up as free form - Please find my code below - I am using the DocuSign REST API to created an embedded signing for a predefined document template using the /envelopes/{envelopeID}/views/recipient call. I am using RESTSHARP to connect to docusign. Thanks much for your help!
protected const string IntegratorKey = "XX";
protected const string Environment = "https://demo.docusign.net";
protected const string templateRole = "Applicant";
protected const string templateId = "XX";
private static Logger logger = LogManager.GetCurrentClassLogger();
protected const string AccountEmail = "XX#XX.com";
protected const string AccountPassword = "***";
private RestSharp.RestClient client = new RestClient();
private RestSharp.RestRequest request;
bool docuSignCallresult = false;
//
// GET: /Docusign/
public ActionResult launchDocusign(int id)
{
RestSettings.Instance.IntegratorKey = IntegratorKey;
RestSettings.Instance.DocuSignAddress = Environment;
RestSettings.Instance.WebServiceUrl = Environment + "/restapi/v2";
Domain.Account currentAccount = null;
using (var accountRepo = new AccountRepository())
{
currentAccount = accountRepo.AccountGet(id);
}
string RecipientEmail = currentAccount.Email;
string RecipientName = currentAccount.FullName;
Account docuSignAcct = GetDocusignAcctDetails();
Envelope docuSignEnvelope = GetDocusignEnvelopeDetails(docuSignAcct,RecipientEmail,RecipientName);
RecipientView rv = GetRecipientView(RecipientEmail, RecipientName);
client = new RestSharp.RestClient(Environment);
request = new RestRequest("/restapi/{apiVersion}/accounts/{accountId}/envelopes/{envelopeId}/views/recipient");
request.AddUrlSegment("apiVersion", "v2");
request.AddUrlSegment("accountId", docuSignAcct.AccountId);
request.AddUrlSegment("envelopeId", docuSignEnvelope.EnvelopeId);
Mysite.Web.Models.DocuSignData.AuthenticationHeader header = new Mysite.Web.Models.DocuSignData.AuthenticationHeader();
var jsonHeader = JsonConvert.SerializeObject(header);
request.AddHeader("X-DocuSign-Authentication", jsonHeader);
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(rv);
var response = client.Execute(request);
char[] charstoTrim = { '\r', '\n', ' ', '\'' };
var json = response.Content.Trim(charstoTrim);
var jo = JObject.Parse(json);
var recipientUrl = jo["url"].ToString();
return Redirect(recipientUrl);
}
/// <summary>
/// Get the recipient view to launch the docusign(Embedded signing experience)
/// </summary>
/// <param name="RecipientEmail"></param>
/// <param name="RecipientName"></param>
/// <returns></returns>
private RecipientView GetRecipientView(string RecipientEmail, string RecipientName)
{
RecipientView rv = new RecipientView();
rv.authenticationMethod = "email";
rv.returnUrl = Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host + "/MySiteController/MySiteActionMethod";
rv.email = RecipientEmail;
rv.userName = RecipientName;
rv.clientUserId = "1";
return rv;
}
/// <summary>
/// Create an Envelope using the template on docusign
/// </summary>
/// <param name="acct"></param>
/// <param name="recipientEmail"></param>
/// <param name="recipientName"></param>
/// <returns></returns>
private Envelope GetDocusignEnvelopeDetails(Account acct,string recipientEmail,string recipientName)
{
Envelope envelope = new Envelope();
envelope.Login = acct;
envelope.Status = "sent";
envelope.EmailSubject = "Testing";
envelope.TemplateId = templateId;
envelope.TemplateRoles = new TemplateRole[]
{
new TemplateRole()
{
email = recipientEmail,
name = recipientName,
roleName = templateRole,
clientUserId = "1"
}
};
try
{
docuSignCallresult = envelope.Create();
}
catch (Exception ex)
{
logger.Error("Login to docusign failed due to {0} and the exception generated is {2}", envelope.RestError.message, ex.Message);
}
return envelope;
}
/// <summary>
/// Access Docusign Account information
/// </summary>
/// <returns></returns>
private Account GetDocusignAcctDetails()
{
Account docuSignAcct = new Account();
docuSignAcct.Email = AccountEmail;
docuSignAcct.Password = AccountPassword;
try
{
docuSignCallresult = docuSignAcct.Login();
}
catch (Exception ex)
{
logger.Error("Login to docusign failed due to {0} and the exception generated is {2}", docuSignAcct.RestError.message, ex.Message);
}
return docuSignAcct;
}
}
}
As Jeff has mentioned in the comments this is most likely caused by you not matching your recipient correctly to a template (placeholder) role on your template. From your code it looks like you are sending the value Applicant as the template role name - this means that you need to have a role called Applicant in your Template in the Web Console.
For instance, in the below screenshot the role name is Signer1:
To fix either login to the Console and name the role on your template "Applicant" or whatever name it currently has copy that into the code and send that in the API request.

401 (Unauthorized) when accessing JIRA API with query string

I'm following the tutorial found here to create a JWT token to access the REST API of JIRA. I do not have any problem accessing endpoints without passing query strings like /rest/api/2/project and /rest/api/2/issue/ISSUE-KEY but I get 401 Unauthorized when trying to pass query strings, say /rest/api/2/user/assignable/search?project=PROJECT-KEY
I'm guessing I'm missing out something, specificially the generation of canonical URL,
Here is the code that generates the get request and JWT token:
#Override
public CloseableHttpResponse get(String url) throws HttpException,
IOException, NoSuchAlgorithmException, ParseException,
JOSEException {
CloseableHttpClient client = HttpClientBuilder.create()
.setUserAgent("Kevin 6.9").build();
String token = createToken(url, JIRAClient.Method.GET);
HttpGet method = new HttpGet(jwt.getBaseUrl() + url);
method.setHeader("Authorization", "JWT " + token);
return client.execute(method);
}
/**
* Create JWT token
*
* #return
* #throws UnsupportedEncodingException
* #throws NoSuchAlgorithmException
*/
private String createToken(String apiPath, JIRAClient.Method method)
throws UnsupportedEncodingException, NoSuchAlgorithmException {
long issuedAt = System.currentTimeMillis() / 1000L;
long expiresAt = issuedAt + 1000L;
String httpMethod = method.toString();
System.out.println(httpMethod);
String contextPath = "/jira";
JwtJsonBuilder jwtBuilder = new JsonSmartJwtJsonBuilder()
.issuedAt(issuedAt).expirationTime(expiresAt)
.issuer(jwt.getKey());
HashMap<String, String[]> parameters = new HashMap<String, String[]>();
CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(
httpMethod, apiPath, contextPath, parameters);
System.out.println("Canonical : " + canonical.getRelativePath());
JwtClaimsBuilder.appendHttpRequestClaims(jwtBuilder, canonical);
JwtWriterFactory jwtWriterFactory = new NimbusJwtWriterFactory();
String jwtbuilt = jwtBuilder.build();
String jwtToken = jwtWriterFactory.macSigningWriter(
SigningAlgorithm.HS256, jwt.getSharedSecret()).jsonToJwt(
jwtbuilt);
return jwtToken;
}
Note that I am passing an empty HashMap<String, String[]> to the CanonicalHttpUriRequest... is this correct?
Apparently the Map<String, String[]> is required to generate the appropriate canonical URI.
Note that I am passing an empty HashMap<String, String[]> to the
CanonicalHttpUriRequest... is this correct?
I modified my method signature so I can pass it as a parameter. Note: createQueryString is a method inside my class that manually creates the query String from the parameter map.
#Override
public CloseableHttpResponse get(String url,
#SuppressWarnings("rawtypes") Map parameters) throws Exception {
CloseableHttpClient client = HttpClientBuilder.create()
.setUserAgent("Kevin 5.0").build();
String token = createToken(url, JIRAClient.Method.GET, parameters);
HttpGet method = new HttpGet(jwt.getBaseUrl() + url
+ createQueryString(parameters));
method.setHeader("Authorization", "JWT " + token);
return client.execute(method);
}
And it works.
#Test
public void testJQL() throws Exception {
HashMap param = new HashMap();
param.put("jql", new String[] {"project=COR"});
param.put("startAt", new String[] {"0"});
HttpResponse response = client.get("/rest/api/2/search", param);
Assert.assertTrue(response.getStatusLine().getStatusCode() == 200);
}

Triple DES without using forward or backward slashes

Is it possible to modify triple DES so as not to include forward and backward slashes when encrypting/decrypting?
I had this actionlink on mvc which works without encryption however when I tried to encrypt the id passed to the controller method, the id was being encrypted and included some forward slashes (/vO5Ppr4+Phzx+lHD4Jp6JubZlYXK0Az9OA9J8urf+MJFw62c3Y0Q/Q==) thus I am getting a 404 not found and the controller method is not being called.
MVC ActionLink:
<span> | </span> #Html.ActionLink("Student Rights", "StudentRights","Threads", new { id = CommonLayer.Securities.Encryption.EncryptTripleDES(item.ID) }, null)
Encryption Method:
private static byte[] KEY_192 =
{
111,21,12,65,21,12,2,1,
5,30,34,78,98,1,32,122,
123,124,125,126,212,212,213,214
};
private static byte[] IV_192 =
{
1,2,3,4,5,12,13,14,
13,14,15,13,17,21,22,23,
24,25,121,122,122,123,124,124
};
/// <summary>
/// Encrypt using TripleDES
/// </summary>
/// <param name="vl">String to Encrypt</param>
/// <returns>Encrypted String</returns>
public static String EncryptTripleDES(String vl)
{
if (vl != "")
{
TripleDESCryptoServiceProvider cryptoprovider = new TripleDESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, cryptoprovider.CreateEncryptor(KEY_192, IV_192), CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(cs);
sw.Write(vl);
sw.Flush();
cs.FlushFinalBlock();
ms.Flush();
return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
}
return "";
}
/// <summary>
/// Decrypt using TripleDES
/// </summary>
/// <param name="vl">String to Decrypt</param>
/// <returns>Decrypted String</returns>
public static String DecryptTripleDES(String vl)
{
if (vl != "")
{
TripleDESCryptoServiceProvider cryptoprovider = new TripleDESCryptoServiceProvider();
Byte[] buffer = Convert.FromBase64String(vl);
MemoryStream ms = new MemoryStream(buffer);
CryptoStream cs = new CryptoStream(ms, cryptoprovider.CreateDecryptor(KEY_192, IV_192), CryptoStreamMode.Read);
StreamReader sw = new StreamReader(cs);
return sw.ReadToEnd();
}
return "";
}
Like owlstead suggests, use the url safe Base64 encoding described in RFC 4648.
My implementation produces a bit much garbage, but for short strings it shouldn't matter much as long as you don't call this a million times a second.
public static string ToUrlSafeBase64(byte[] bytes)
{
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').Replace("=","");
}
public static byte[] FromUrlSafeBase64(string s)
{
while (s.Length % 4 != 0)
s += "=";
s = s.Replace('-', '+').Replace('_', '/');
return Convert.FromBase64String(s);
}
Used as:
var str = ToUrlSafeBase64(bytes);
var bytes = FromUrlSafeBase64(str);
That's not the output of 3DES, that's Base 64 encoding of random (looking) binary data.
You can simply (raw) URL-encode the result or you can replace the character by any other. Check the Base 64 page on Wikipedia for ideas. Try and keep to common standards, such a replacing the + with -, and replacing / with _ as standardized by RFC 4648.
You may also want to remove the = characters at the end. This works if your base 64 library can decode such base 64, otherwise you can simply append them again until you got a string that has a multiple of 4 base 64 characters.
the following functions worked on another post why-is-base64-encode-adding-a-slash-in-the-result
function mybase64_encode($s) {
return str_replace(array('+', '/'), array(',', '-'), base64_encode($s));
}
function mybase64_decode($s) {
return base64_decode(str_replace(array(',', '-'), array('+', '/'), $s));
}

Windows 8 Httpclient basic authentcation

I am new to this forum.
I am trying to do Basic authentication using Httclient for my Windows app.
var handler2 = new HttpClientHandler
{
Credentials = new NetworkCredential(username, password)
};
var httpClient2 = new HttpClient(handler2);
httpClient2.DefaultRequestHeaders.Add("user-Agent", "authentication.cs");
var response2 = httpClient.GetAsync(uri);
I have 2 questions:
I need to add header content type and user-agent. Dont know how to add them. Could someone help me out.
In response i am getting null values. Any idea why?
Regards,
TM
You can add the user agent header by doing
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("authentication.cs"));
You can't add Content-Type to the default request headers because you can only set Content-Type when you are sending some Content using a PUT or a POST.
I'm guessing you want to set the Accept header like this:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
Update: Without my own account, this is as far as I can go.
public sealed partial class MainPage : Page
{
private readonly HttpClient _httpClient = new HttpClient();
public MainPage()
{
this.InitializeComponent();
InitHttpClient();
}
private void InitHttpClient() {
var username = "youremail#somewhere.com";
var password = "yourharvestpassword";
String authparam = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(username + ":" + password));
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authparam);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MyHarvestClient", "1.0"));
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e) {
_httpClient.GetAsync("https://yoursubdomain.harvestapp.com/projects")
.ContinueWith(t => HandleResponse(t.Result));
}
private void HandleResponse(HttpResponseMessage response) {
response.EnsureSuccessStatusCode();
var contentString = response.Content.ReadAsStringAsync().Result;
var contentXML = XDocument.Parse(contentString);
}
}

Where to find C# sample code to implement password recovery in ASP .NET MVC2

How to implement password reset in MVC2 application?
Passwords are hashed using ASP .NET membership provider. Password recovery question is not used. Standard ASP .NET MVC2 project template with standard AccountController class is used.
If user forgots password, email with temporary link or with new password should sent to user e-mail address .
Where to find code to implement this in MVC 2 C# ?
stack overflow contains two answers which discuss methods about implementing this. There is not sample code.
I googled for "asp .net mvc password reset c# sample code download" but havent found sample code for this.
I'm new to MVC. Where to find sample code for password recovery? This is missing from VS2010 generated project template.
Update
I tried this code in Mono 2.10 but got exception:
CspParameters not supported by Mono
at line
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
How to run it in Mono ?
Stack Trace:
System.NotSupportedException: CspParameters not supported by Mono
at System.Security.Cryptography.PasswordDeriveBytes.CryptDeriveKey (string,string,int,byte[]) [0x0001b] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs:197
at store2.Helpers.Password.EncodeMessageWithPassword (string,string) <IL 0x00055, 0x000f3>
at store2.Helpers.AccountHelper.GetTokenForValidation (string) <IL 0x00033, 0x00089>
at MvcMusicStore.Controllers.AccountController.PasswordReminder (MvcMusicStore.Models.PasswordReminderModel) <IL 0x001ac, 0x00495>
at (wrapper dynamic-method) System.Runtime.CompilerServices.ExecutionScope.lambda_method (System.Runtime.CompilerServices.ExecutionScope,System.Web.Mvc.ControllerBase,object[]) <IL 0x00020, 0x0005b>
at System.Web.Mvc.ActionMethodDispatcher.Execute (System.Web.Mvc.ControllerBase,object[]) <IL 0x00008, 0x0001b>
at System.Web.Mvc.ReflectedActionDescriptor.Execute (System.Web.Mvc.ControllerContext,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00072, 0x00103>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod (System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00003, 0x00019>
at System.Web.Mvc.ControllerActionInvoker/<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a () <IL 0x0002d, 0x00068>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (System.Web.Mvc.IActionFilter,System.Web.Mvc.ActionExecutingContext,System.Func`1<System.Web.Mvc.ActionExecutedContext>) <IL 0x00031, 0x000b6>
--------------------------------------------------------------------------------
Version information: Mono Runtime Version: 2.10.2 (tarball Mon Apr 18 18:57:39 UTC 2011); ASP.NET Version: 2.0.50727.1433
Here is my approach. In MVC you will have an action called RetrievePassword where you will ask for the user's email address and pass it in a post
[HttpGet]
public ActionResult RetrievePassword()
{
return View();
}
[HttpPost]
public ActionResult RetrievePassword(PasswordRetrievalModel model)
{
if (ModelState.IsValid)
{
string username = Membership.GetUserNameByEmail(model.Email);
if (!String.IsNullOrEmpty(username))
{
// This is a helper function that sends an email with a token (an MD5).
NotificationsHelper.SendPasswordRetrieval(model.Email, this.ControllerContext);
}
else
{
Trace.WriteLine(String.Format("*** WARNING: A user tried to retrieve their password but the email address used '{0}' does not exist in the database.", model.Email));
}
return RedirectToAction("Index", "Home");
}
return View(model);
}
An email message will be sent with a url that redirects to http://example.com/Account/Validate?email=xxxxxxxx&token=xxxxxxxx
If the token is valid for the email, you will probably display a password reset form so they choose a new password.
So you need a Validate Action:
[HttpGet]
[CompressFilter]
public ActionResult Validate(string email, string token)
{
bool isValid = false;
if (AccountHelper.IsTokenValid(token, email))
{
string username = Membership.GetUserNameByEmail(email);
if (!String.IsNullOrEmpty(username))
{
// Get the user and approve it.
MembershipUser user = Membership.GetUser(username);
user.IsApproved = true;
Membership.UpdateUser(user);
isValid = true;
// Since it was a successful validation, authenticate the user.
FormsAuthentication.SetAuthCookie(username, false);
}
else
{
isValid = false;
}
}
return View(isValid);
}
Here are some of the helpers you see in this code:
Account Helper
/// <summary>
/// Gets the token for invitation.
/// </summary>
/// <param name="email">The email.</param>
/// <returns></returns>
public static string GetTokenForInvitation(string email)
{
if (String.IsNullOrEmpty(email))
throw new ArgumentException("The email cannot be null");
string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);
return token;
}
/// <summary>
/// Gets the email from token.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="email">The email.</param>
/// <returns></returns>
public static bool GetEmailFromToken(string token, out string email)
{
email = String.Empty;
string message = Password.DecodeMessageWithPassword(token, SEED);
string[] messageParts = message.Split('#');
if (messageParts.Count() != 2)
{
return false;
// the token was not generated correctly.
}
else
{
email = messageParts[0];
return true;
}
}
/// <summary>
/// Helper function used to generate a token to be used in the message sent to users when registered the first time to confirm their email address.
/// </summary>
/// <param name="email">The email address to encode.</param>
/// <returns>The token generated from the email address, timestamp, and SEED value.</returns>
public static string GetTokenForValidation(string email)
{
if (String.IsNullOrEmpty(email))
throw new ArgumentException("The email cannot be null");
string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);
return token;
}
/// <summary>
/// Validates whether a given token is valid for a determined email address.
/// </summary>
/// <param name="token">The token to validate.</param>
/// <param name="email">The email address to use in the validation.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
public static bool IsTokenValid(string token, string email)
{
return IsTokenValid(token, email, DateTime.Now);
}
/// <summary>
/// Core method to validate a token that also offers a timestamp for testing. In production mode should always be DateTime.Now.
/// </summary>
/// <param name="token">The token to validate.</param>
/// <param name="email">the email address to use in the validation.</param>
/// <param name="timestamp">The timestamp representing the time in which the validation is performed.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
public static bool IsTokenValid(string token, string email, DateTime timestamp)
{
if (String.IsNullOrEmpty(token))
throw new ArgumentException("The token cannot be null");
try
{
string message = Password.DecodeMessageWithPassword(token, SEED);
string[] messageParts = message.Split('#');
if (messageParts.Count() != 2)
{
return false;
// the token was not generated correctly.
}
else
{
string messageEmail = messageParts[0];
string messageDate = messageParts[1];
// If the emails are the same and the date in which the token was created is no longer than 5 days, then it is valid. Otherwise, it is not.
return (String.Compare(email, messageEmail, true) == 0 && timestamp.Subtract(DateTime.Parse(messageDate)).Days < 5);
}
}
catch (Exception)
{
// could not decrypt the message. The token has been tampered with.
return false;
}
}
And Finally here some code to encrypt, decript a token...
I have it in a Password class that is intended to be a helper.
/// EDIT:
Removed the two functions I referenced before and show the full helper class.
Here is the Password static class with all helper functions.
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Data;
using System.Resources;
namespace MySolution.Common.Util
{
/// <summary>
/// Implements some functions to support password manipulation or generation
/// </summary>
public class Password
{
/// <summary>
/// Takes a string and generates a hash value of 16 bytes.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
/// <returns>A hex string of the hashed password.</returns>
public static string EncodeString(string str, string passwordFormat)
{
if (str == null)
return null;
ASCIIEncoding AE = new ASCIIEncoding();
byte[] result;
switch (passwordFormat)
{
case "sha1":
SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
result = sha1.ComputeHash(AE.GetBytes(str));
break;
case "md5":
MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
result = md5.ComputeHash(AE.GetBytes(str));
break;
default:
throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
}
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x2"));
}
return sb.ToString();
}
/// <summary>
/// Takes a string and generates a hash value of 16 bytes. Uses "md5" by default.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <returns>A hex string of the hashed password.</returns>
public static string EncodeString(string str)
{
return EncodeString(str, "md5");
}
/// <summary>
/// Takes a string and generates a hash value of 16 bytes.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
/// <returns>A string of the hashed password.</returns>
public static string EncodeBinary(byte[] buffer, string passwordFormat)
{
if (buffer == null)
return null;
byte[] result;
switch (passwordFormat)
{
case "sha1":
SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
result = sha1.ComputeHash(buffer);
break;
case "md5":
MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
result = md5.ComputeHash(buffer);
break;
default:
throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
}
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x2"));
}
return sb.ToString();
}
/// <summary>
/// Encodes the buffer using the default cryptographic provider.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
public static string EncodeBinary(byte[] buffer)
{
return EncodeBinary(buffer, "md5");
}
/// <summary>
/// Creates a random alphanumeric password.
/// </summary>
/// <returns>A default length character string with the new password.</returns>
/// <remarks>The default length of the password is eight (8) characters.</remarks>
public static string CreateRandomPassword()
{
//Default length is 8 characters
return CreateRandomPassword(8);
}
/// <summary>
/// Creates a random alphanumeric password on dimension (Length).
/// </summary>
/// <param name="Length">The number of characters in the password</param>
/// <returns>The generated password</returns>
public static string CreateRandomPassword(int Length)
{
Random rnd = new Random(Convert.ToInt32(DateTime.Now.Millisecond)); //Creates the seed from the time
string Password="";
while (Password.Length < Length )
{
char newChar = Convert.ToChar((int)((122 - 48 + 1) * rnd.NextDouble() + 48));
if ((((int) newChar) >= ((int) 'A')) & (((int) newChar) <= ((int) 'Z')) | (((int) newChar) >= ((int) 'a')) & (((int) newChar) <= ((int) 'z')) | (((int) newChar) >= ((int) '0')) & (((int) newChar) <= ((int) '9')))
Password += newChar;
}
return Password;
}
/// <summary>
/// Takes a text message and encrypts it using a password as a key.
/// </summary>
/// <param name="plainMessage">A text to encrypt.</param>
/// <param name="password">The password to encrypt the message with.</param>
/// <returns>Encrypted string.</returns>
/// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
public static string EncodeMessageWithPassword(string plainMessage, string password)
{
if (plainMessage == null)
throw new ArgumentNullException("encryptedMessage", "The message cannot be null");
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.IV = new byte[8];
//Creates the key based on the password and stores it in a byte array.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
MemoryStream ms = new MemoryStream(plainMessage.Length * 2);
CryptoStream encStream = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainMessage);
encStream.Write(plainBytes, 0, plainBytes.Length);
encStream.FlushFinalBlock();
byte[] encryptedBytes = new byte[ms.Length];
ms.Position = 0;
ms.Read(encryptedBytes, 0, (int)ms.Length);
encStream.Close();
return Convert.ToBase64String(encryptedBytes);
}
/// <summary>
/// Takes an encrypted message using TripleDES and a password as a key and converts it to the original text message.
/// </summary>
/// <param name="encryptedMessage">The encrypted message to decode.</param>
/// <param name="password">The password to decode the message.</param>
/// <returns>The Decrypted message</returns>
/// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
public static string DecodeMessageWithPassword(string encryptedMessage, string password)
{
if (encryptedMessage == null)
throw new ArgumentNullException("encryptedMessage", "The encrypted message cannot be null");
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.IV = new byte[8];
//Creates the key based on the password and stores it in a byte array.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
//This line protects the + signs that get replaced by spaces when the parameter is not urlencoded when sent.
encryptedMessage = encryptedMessage.Replace(" ", "+");
MemoryStream ms = new MemoryStream(encryptedMessage.Length * 2);
CryptoStream decStream = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
byte[] plainBytes;
try
{
byte[] encBytes = Convert.FromBase64String(Convert.ToString(encryptedMessage));
decStream.Write(encBytes, 0, encBytes.Length);
decStream.FlushFinalBlock();
plainBytes = new byte[ms.Length];
ms.Position = 0;
ms.Read(plainBytes, 0, (int)ms.Length);
decStream.Close();
}
catch(CryptographicException e)
{
throw new ApplicationException("Cannot decrypt message. Possibly, the password is wrong", e);
}
return Encoding.UTF8.GetString(plainBytes);
}
}
}
Set a Reset password GUID in user table. You may also use an expiration time. If user tried to reset password, update the field with a new GUID and datetime for expiration.
Send a link containing the link to reset password with the GUID.
A sample function like this can be created for that
GUID res = objPasswordResetService.resetPassword(Convert.ToInt64(objUserViewModel.UserID), restpasswordGuid, resetPasswordExpiryDateTime);
The value in res can be the GUID updated in DB. Send a link with this GUID. You can check the expiration time also. This is just an idea only
I've got an example of how to implement password recovery in a standard ASP.NET MVC application in my blog.
This blog post assumes that you already have the login process working (database and all) and that you only need to wire the password recovery process.
http://hectorcorrea.com/Blog/Password-Recovery-in-an-ASP.NET-MVC-Project
Answer to implement password reset in MVC2 application
public string ResetPassword(string userName)
{
MembershipUser user = _provider.GetUser(userName, false);
if (user.IsLockedOut)
user.UnlockUser();
user.Comment = null;
_provider.UpdateUser(user);
string newPassword = user.ResetPassword();
string friendlyPassword = GenerateNewPassword();
_provider.ChangePassword(userName, newPassword, friendlyPassword);
return friendlyPassword;
}
private string GenerateNewPassword()
{
string strPwdchar = "abcdefghijklmnopqrstuvwxyz0123456789##$ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string strPwd = "";
Random rnd = new Random();
for (int i = 0; i <= 8; i++)
{
int iRandom = rnd.Next(0, strPwdchar.Length - 1);
strPwd += strPwdchar.Substring(iRandom, 1);
}
return strPwd;
}
here the russian version password recovery

Resources