Based on the documentation, with provided sample data, it should be possible to generate a signed key with value of:
aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404
Here is my code in .Net:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace PlayingWithAmazonS3
{
public class ReadTextFilePerRest
{
private string _regionSample = "us-east-1";
private string _dateSample = "20130524";
private string _secretAccessKeySample = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
private string _canonicalRequestPath = "..\\Files\\SampleFiles\\CanonicalRequest.txt";
private string _stringToSignPath = "..\\Files\\SampleFiles\\StringToSign.txt";
private string _canonicalRequest;
private string _stringToSign;
public void ReadPayloadFiles()
{
_stringToSign = File.ReadAllText(_stringToSignPath);
_canonicalRequest = File.ReadAllText(_canonicalRequestPath);
}
// it needs to return: aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404
public string SigningKey()
{
var keyBytes = Encoding.ASCII.GetBytes("AWS4" + _secretAccessKeySample);
var dateBytes = Encoding.ASCII.GetBytes(_dateSample);
var regionBytes = Encoding.ASCII.GetBytes(_regionSample);
var serviceBytes = Encoding.ASCII.GetBytes("s3");
var requestBytes = Encoding.ASCII.GetBytes("aws4_request");
var stringToSignBytes = Encoding.ASCII.GetBytes(_stringToSign);
using (HMACSHA256 hmac = new HMACSHA256(dateBytes))
{
var dateKey = hmac.ComputeHash(keyBytes);
using (HMACSHA256 hmac2 = new HMACSHA256(regionBytes))
{
var dateRegionKey = hmac2.ComputeHash(dateKey);
using (HMACSHA256 hmac3 = new HMACSHA256(serviceBytes))
{
var dateRegionServiceKey = hmac3.ComputeHash(dateRegionKey);
using (HMACSHA256 hmac4 = new HMACSHA256(requestBytes))
{
var signingKey = hmac4.ComputeHash(dateRegionServiceKey);
using (HMACSHA256 hmac5 = new HMACSHA256(stringToSignBytes))
{
var signature = hmac5.ComputeHash(signingKey);
return ByteToString(signature);
}
}
}
}
}
}
private string ByteToString(IEnumerable<byte> buffer)
{
var sBinary = buffer.Aggregate("", (current, buff) => current + buff.ToString("X2"));
return sBinary;
}
}
}
However, my generated signed key is different. Can anybody tell me where is my mistake?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace PlayingWithAmazonS3
{
/// <summary>
/// this class is only responsible for calculating the final signature for creating a pre-signed Url to
/// communicate through REST with iam service
/// </summary>
public class PreSignedUrlRestSignatureCal
{
private const string RegionSample = "us-east-1";
private const string DateSample = "20150830";
private const string ServiceSample = "iam";
// it is provided as an example by AWS
private const string SecretAccessKeySample = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
/// <summary>
/// this method will be called in main
/// </summary>
public void ExecuteMethod()
{
var finalSignature = SigningKey();
Console.WriteLine("Final Signature: " + finalSignature);
}
private string SigningKey()
{
// generating derived signing key
var derivedSigningKey =
GetSignatureKey(SecretAccessKeySample, DateSample, RegionSample, ServiceSample);
// example signingKey provided by aws for test
var stringToSign = "AWS4-HMAC-SHA256" + "\n" +
"20150830T123600Z" + "\n" +
"20150830/us-east-1/iam/aws4_request" + "\n" +
"f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59";
// generating the final signature
var signature = HmacSha256(stringToSign, derivedSigningKey);
// returning the hex value of the final signature
return ByteToString(signature);
}
/// <summary>
/// calculating hmac-sha256 in .Net
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
private byte[] HmacSha256(string data, byte[] key)
{
const string algorithm = "HmacSHA256";
var kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
/// <summary>
/// get derived signing key (not the final signature) from provided info
/// </summary>
/// <param name="key"></param>
/// <param name="dateStamp"></param>
/// <param name="regionName"></param>
/// <param name="serviceName"></param>
/// <returns></returns>
private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
var kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
var kDate = HmacSha256(dateStamp, kSecret);
var kRegion = HmacSha256(regionName, kDate);
var kService = HmacSha256(serviceName, kRegion);
var kSigning = HmacSha256("aws4_request", kService);
return kSigning;
}
/// <summary>
/// it returns the hex value of byte[]
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
private string ByteToString(IEnumerable<byte> buffer)
{
var sBinary = buffer.Aggregate("", (current, buff) => current + buff.ToString("X2"));
return sBinary.ToLower();
}
}
}
Related
I have multi-level json coming from aws secret and I want to bind this json or secret with the configuration of c# so that I can use it in the whole project.
public class AmazonSecretsManagerConfigurationProvider : ConfigurationProvider
{
private readonly string _region;
private readonly string _secretName;
/// <summary>
/// Initializes a new instance of the <see cref="AmazonSecretsManagerConfigurationProvider"/> class.
/// </summary>
/// <param name="region"></param>
/// <param name="secretName"></param>
public AmazonSecretsManagerConfigurationProvider(string region, string secretName)
{
_region = region;
_secretName = secretName;
}
public override void Load()
{
var secret = GetSecret();
Dictionary<string, object> data = JsonConvert.DeserializeObject<Dictionary<string, object>>(secret);
Dictionary<string, string> Data = data.ToDictionary(k => k.Key, k => k.Value.ToString());
}
private string GetSecret()
{
var request = new GetSecretValueRequest
{
SecretId = "awsseceret",
VersionStage = "AWSCURRENT" // VersionStage defaults to AWSCURRENT if unspecified.
};
string accesskey = "################";
string secretkey = "#######################";
using (var client =
new AmazonSecretsManagerClient(accesskey, secretkey, RegionEndpoint.GetBySystemName(this._region)))
{
var response = client.GetSecretValueAsync(request).Result;
string secretString;
if (response.SecretString != null)
{
secretString = response.SecretString;
}
else
{
var memoryStream = response.SecretBinary;
var reader = new StreamReader(memoryStream);
secretString =
System.Text.Encoding.UTF8
.GetString(Convert.FromBase64String(reader.ReadToEnd()));
}
return secretString;
}
}
}
}
I get aws secretString in the secret variable but how can I bind this to the configuration?
I modify my WIN7 computer's registry via c#,but it dosen't work.
my code likes below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32; //添加针对操作注册表的应用
namespace operateToolWPF.Utils
{
class RegisterHelper
{
public static string GetRegistryData(RegistryKey root, string subKey,
string name)
{
string registData = string.Empty;
RegistryKey myKey = root.OpenSubKey(subKey, true);
if (myKey != null)
{
registData = myKey.GetValue(name).ToString();
}
return registData;
}
/// <summary>
/// 向注册表中写数据
/// </summary>
/// <param name="root"></param>
/// <param name="subKey"></param>
/// <param name="keyName"></param>
/// <param name="keyValue"></param>
public static void SetRegistryData(RegistryKey root, string subKey, string keyName, Int32 keyValue)
{
RegistryKey aimDir = root.CreateSubKey(subKey);
aimDir.SetValue(keyName, keyValue, RegistryValueKind.DWord);
}
/// <summary>
/// 删除注册表中指定的注册项
/// </summary>
/// <param name="root"></param>
/// <param name="subKey"></param>
/// <param name="keyName"></param>
public static void DeleteRegist(RegistryKey root, string subKey, string keyName)
{
string[] subkeyNames;
RegistryKey myKey = root.OpenSubKey(subKey, true);
subkeyNames = myKey.GetSubKeyNames();
foreach (string aimKey in subkeyNames)
{
if (aimKey == keyName)
myKey.DeleteSubKeyTree(keyName);
}
}
/// <summary>
/// 判断指定注册表项是否存在
/// </summary>
/// <param name="root"></param>
/// <param name="subKey"></param>
/// <param name="keyName"></param>
/// <returns></returns>
public static bool IsRegistryExits(RegistryKey root, string subKey, string keyName)
{
bool result = false;
string[] subKeyNames;
RegistryKey myKey = root.OpenSubKey(subKey, true);
subKeyNames = myKey.GetValueNames();
foreach (string name in subKeyNames)
{
if (name == keyName)
{
result = true;
return result;
}
}
return result;
}
}
}
and then call it like this:
//获取当前Windows用户
WindowsIdentity curUser = WindowsIdentity.GetCurrent();
//用户SID
SecurityIdentifier sid = curUser.User;
//用户全称
NTAccount ntacc = (NTAccount)sid.Translate(typeof(NTAccount));
Console.WriteLine("Windows SID:" + sid.Value);
Console.WriteLine("用户全称:" + ntacc.Value);
Int32 tempInt = 0; //预先定义一个有符号32位数
//unchecked语句块内的转换,不做溢出检查
unchecked
{
tempInt = Convert.ToInt32("00000000", 16); //强制转换成有符号32位数
}
//读取Display Inline Images
string displayImgPath = sid.Value + #"\Software\Microsoft\Windows\CurrentVersion\Internet Settings";
string ProxyEnable = RegisterHelper.GetRegistryData(Registry.Users, displayImgPath, "ProxyEnable");
//此时的tempInt已经是有符号32位数,可以直接写入注册表
RegisterHelper.SetRegistryData(Registry.Users, displayImgPath, "ProxyEnable", tempInt);
Thread.Sleep(3000);
RegisterHelper.DeleteRegist(Registry.Users, displayImgPath, "ProxyServer");
RegisterHelper.DeleteRegist(Registry.Users, displayImgPath, "ProxyOverride");
Registry.Users.Close();
Process[] MyProcess = Process.GetProcessesByName("explorer");
MyProcess[0].Kill();
by all this ,i want modify ProxyEnable and delete ProxyOverride,ProxyServer,which was cancel IE proxy setting.
I have tried several methodes,but have no one can cancel IE proxy setting.
Can you help me? Thanks!
Here is an example of how I would implement registry IO as you have tried to do. Depending on which part of the registry you are trying to read/write from may use different keys:
public class MyReg{
public RegistryKey Foriegnkey {
get => forignKey;
set => forignKey = value;
}
private RegistryKey forignKey;
public object Read(string Path, string Name) => (Registry.CurrentUser.OpenSubKey(Path, false).GetValue(Name));
public void Write(string Path, string Name, object Data) {
Foriegnkey = Registry.CurrentUser.CreateSubKey(Path, RegistryKeyPermissionCheck.Default);
Foriegnkey.SetValue(Name, Data);
Foriegnkey.Close();
}
}
The example above will read / write at Current User level, but there are other levels which can be used, and you will see these as available options within IntelliSense
You can use this in your application by assigning an instance of your registry class to an object and just calling registry.read/write etc …
This can be checked for nulls using :
if (Registry.GetValue(#"HKEY_CURRENT_USER\Software\MyApp", "SomeValue", null) == null)
And when you come to write data you can use:
myregobject.Write(#"\software\MyApp", "SomeValue", "hello world!");
In your case this enables you to do the following:
if (!Registry.GetValue(#"\Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", null) == null) {
myregobject.Write(#"\Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", "your data here")
}
I cant tell if your delete method works or not from looking at it so i'll throw in my input there as well:
public void RemoveKey(string FolderName) {
Registry.CurrentUser.DeleteSubKeyTree(FolderName);
}
Hope this helps!
This references my last question which appears to have been abandoned. I am experiencing an odd "bug" if you will with C# and MS VS 2015. To reproduce the error, follow the steps:
Open console app project and copy paste code below.
Set a break point here:
First run code past break point, it works! :D
Then run code again but this time STOP at the break point and DRAG the executing statement cursor INTO the if statement from here:
to here:
Hit Continue and an NRE exception is thrown. Why does this happen? Is it just me? What is the technical explination for this?
CODE:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace testapp
{
class Program
{
static void Main(string[] args)
{
FILECollection randomCollection = new FILECollection();
// Fill with junk test data:
for(int i = 0; i<10; i++)
{
FILE junkfile = new FILE() { fileName = i.ToString(), folderName = i.ToString(), fileHashDigest = new byte[1] };
randomCollection.Add(junkfile);
}
if (true)
{
Console.WriteLine("testing this weird exception issue...");
FILE test;
test = new FILE();
test.fileName = "3";
test.folderName = "3";
test.fileHashDigest = new byte[1];
FILE exists = randomCollection.Where(f => f.fileName == test.fileName &&
f.fileHashDigest.SequenceEqual(test.fileHashDigest)).First();
}
}
}
public class FILE
{
public FILE() { _fileName = "";}
private string _fileName;
public string fileName
{
get
{
if (false)
return this._fileName.ToUpper();
else
return this._fileName;
}
set
{
if (false)
this._fileName = value.ToUpper();
else
this._fileName = value;
}
}
public string folderName { get; set; }
public byte[] fileHashDigest { get; set; }
}
public class FILECollection : IEnumerable<FILE>, ICollection<FILE>
{
private HashSet<FILE> svgHash;
private static List<FILE> PreallocationList;
public string FileName = "N/A";
/// <summary>
/// Default Constructor, will not
/// preallocate memory.
/// </summary>
/// <param name="PreallocationSize"></param>
public FILECollection()
{
this.svgHash = new HashSet<FILE>();
this.svgHash.Clear();
}
/// <summary>
/// Overload Constructor Preallocates
/// memory to be used for the new
/// FILE Collection.
/// </summary>
public FILECollection(int PreallocationSize, string fileName = "N/A", int fileHashDigestSize = 32)
{
FileName = fileName;
PreallocationList = new List<FILE>(PreallocationSize);
for (int i = 0; i <= PreallocationSize; i++)
{
byte[] buffer = new byte[fileHashDigestSize];
FILE preallocationSVG = new FILE()
{
fileName = "",
folderName = "",
fileHashDigest = buffer
};
PreallocationList.Add(preallocationSVG);
}
this.svgHash = new HashSet<FILE>(PreallocationList);
this.svgHash.Clear(); // Capacity remains unchanged until a call to TrimExcess is made.
}
/// <summary>
/// Add an FILE file to
/// the FILE Collection.
/// </summary>
/// <param name="svg"></param>
public void Add(FILE svg)
{
this.svgHash.Add(svg);
}
/// <summary>
/// Removes all elements
/// from the FILE Collection
/// </summary>
public void Clear()
{
svgHash.Clear();
}
/// <summary>
/// Determine if the FILE collection
/// contains the EXACT FILE file, folder,
/// and byte[] sequence. This guarantees
/// that the collection contains the EXACT
/// file you are looking for.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(FILE item)
{
return svgHash.Any(f => f.fileHashDigest.SequenceEqual(item.fileHashDigest) &&
f.fileName == item.fileName &&
f.folderName == item.folderName);
}
/// <summary>
/// Determine if the FILE collection
/// contains the same file and folder name,
/// byte[] sequence is not compared. The file and folder
/// name may be the same but this does not guarantee the
/// file contents are exactly the same. Use Contains() instead.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool ContainsPartially(FILE item)
{
return svgHash.Any(f => f.fileName == item.fileName &&
f.folderName == item.folderName);
}
/// <summary>
/// Returns the total number
/// of FILE files in the Collection.
/// </summary>
public int Count
{ get { return svgHash.Count(); } }
public bool IsReadOnly
{ get { return true; } }
public void CopyTo(FILE[] array, int arrayIndex)
{
svgHash.CopyTo(array, arrayIndex);
}
public bool Remove(FILE item)
{
return svgHash.Remove(item);
}
public IEnumerator<FILE> GetEnumerator()
{
return svgHash.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return svgHash.GetEnumerator();
}
}
}
I think either I am debugging in a terribly wrong way, or Microsoft should take a look at this. It's like future code is breaking current code...which is impossible!
OK here's my best guess..
First, as I mentioned in the comments, the exception doesn't occur if you comment out the line FILE exists = randomCollection.Where(f => f.fileName == test.fileName && f.fileHashDigest.SequenceEqual(test.fileHashDigest)).First();
Second, I noticed the same behavior can be reproduced with the following code:
if (true)
{
object o;
o = new object();
Func<bool> m = () => o == null;
}
i.e. the cause seems to be related to the variable being used in a lambda expression. So, looking at the same code snippet above in ILSpy I get the following:
Program.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.<>c__DisplayClass0_0();
<>c__DisplayClass0_.o = new object();
Func<bool> func = new Func<bool>(<>c__DisplayClass0_.<Main>b__0);
so my best guess is that the NullReferenceException refers to <>c__DisplayClass0_ intance being null - and I'm therefore inclined to believe that the stepping through the if(true) actually skipped the first line where <>c__DisplayClass0_ is instantiated
I have added identity framework to my WebApi and followed the steps outlined here:
http://bitoftech.net/2015/01/21/asp-net-identity-2-with-asp-net-web-api-2-accounts-management/
All of this is working fine.
The problem I have, is that my client has another system of which the API integrates with (to collect data) and that has it's own login methods. So, with that in mind, my client has asked me to use a CustomPasswordHasher to encrypt and decrypt passwords.
What they would like to do is be able to get a password hash and convert it into the actual password so that they can use it to log into the old system (both passwords / accounts will be the same).
I know this is very unothadox but I have no choice in the matter.
My question is, how easy is this to do?
I have found a few topics on how to create a custom password hasher, but none show me how to actually get the password from the hashed password, they only show how to compare.
Currently I have this:
public class PasswordHasher : IPasswordHasher
{
private readonly int _saltSize;
private readonly int _bytesRequired;
private readonly int _iterations;
public PasswordHasher()
{
this._saltSize = 128 / 8;
this._bytesRequired = 32;
this._iterations = 1000;
}
public string HashPassword(string password)
{
// Create our defaults
var array = new byte[1 + this._saltSize + this._bytesRequired];
// Try to hash our password
using (var pbkdf2 = new Rfc2898DeriveBytes(password, this._saltSize, this._iterations))
{
var salt = pbkdf2.Salt;
Buffer.BlockCopy(salt, 0, array, 1, this._saltSize);
var bytes = pbkdf2.GetBytes(this._bytesRequired);
Buffer.BlockCopy(bytes, 0, array, this._saltSize + 1, this._bytesRequired);
}
// Return the password base64 encoded
return Convert.ToBase64String(array);
}
public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
// Throw an error if any of our passwords are null
ThrowIf.ArgumentIsNull(() => hashedPassword, () => providedPassword);
// Get our decoded hash
var decodedHashedPassword = Convert.FromBase64String(hashedPassword);
// If our password length is 0, return an error
if (decodedHashedPassword.Length == 0)
return PasswordVerificationResult.Failed;
var t = decodedHashedPassword[0];
// Do a switch
switch (decodedHashedPassword[0])
{
case 0x00:
return PasswordVerificationResult.Success;
default:
return PasswordVerificationResult.Failed;
}
}
private bool VerifyHashedPassword(byte[] hashedPassword, string password)
{
// If we are not matching the original byte length, then we do not match
if (hashedPassword.Length != 1 + this._saltSize + this._bytesRequired)
return false;
//// Get our salt
//var salt = pbkdf2.Salt;
//Buffer.BlockCopy(salt, 0, array, 1, this._saltSize);
//var bytes = pbkdf2.GetBytes(this._bytesRequired);
//Buffer.BlockCopy(bytes, 0, array, this._saltSize + 1, this._bytesRequired);
return true;
}
}
If I really wanted to I could just do this:
public class PasswordHasher : IPasswordHasher
{
public string HashPassword(string password)
{
// Do no hashing
return password;
}
public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
// Throw an error if any of our passwords are null
ThrowIf.ArgumentIsNull(() => hashedPassword, () => providedPassword);
// Just check if the two values are the same
if (hashedPassword.Equals(providedPassword))
return PasswordVerificationResult.Success;
// Fallback
return PasswordVerificationResult.Failed;
}
}
but that would be crazy, because all the passwords would be stored as plain text. Surely there is a way to "encrypt" the password and "decrypt" it when I make a call?
So, I have tried to be as secure as possible. This is what I have done.
I created a new provider:
public class AdvancedEncryptionStandardProvider
{
// Private properties
private readonly ICryptoTransform _encryptor, _decryptor;
private UTF8Encoding _encoder;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="key">Our shared key</param>
/// <param name="secret">Our secret</param>
public AdvancedEncryptionStandardProvider(string key, string secret)
{
// Create our encoder
this._encoder = new UTF8Encoding();
// Get our bytes
var _key = _encoder.GetBytes(key);
var _secret = _encoder.GetBytes(secret);
// Create our encryptor and decryptor
var managedAlgorithm = new RijndaelManaged();
managedAlgorithm.BlockSize = 128;
managedAlgorithm.KeySize = 128;
this._encryptor = managedAlgorithm.CreateEncryptor(_key, _secret);
this._decryptor = managedAlgorithm.CreateDecryptor(_key, _secret);
}
/// <summary>
/// Encrypt a string
/// </summary>
/// <param name="unencrypted">The un-encrypted string</param>
/// <returns></returns>
public string Encrypt(string unencrypted)
{
return Convert.ToBase64String(Encrypt(this._encoder.GetBytes(unencrypted)));
}
/// <summary>
/// Decrypt a string
/// </summary>
/// <param name="encrypted">The encrypted string</param>
/// <returns></returns>
public string Decrypt(string encrypted)
{
return this._encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
}
/// <summary>
/// Encrypt some bytes
/// </summary>
/// <param name="buffer">The bytes to encrypt</param>
/// <returns></returns>
public byte[] Encrypt(byte[] buffer)
{
return Transform(buffer, this._encryptor);
}
/// <summary>
/// Decrypt some bytes
/// </summary>
/// <param name="buffer">The bytes to decrypt</param>
/// <returns></returns>
public byte[] Decrypt(byte[] buffer)
{
return Transform(buffer, this._decryptor);
}
/// <summary>
/// Writes bytes to memory
/// </summary>
/// <param name="buffer">The bytes</param>
/// <param name="transform"></param>
/// <returns></returns>
protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
{
// Create our memory stream
var stream = new MemoryStream();
// Write our bytes to the stream
using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
// Retrun the stream as an array
return stream.ToArray();
}
}
Then my PasswordHasher, I changed to this:
public class PasswordHasher : IPasswordHasher
{
// Private properties
private readonly AdvancedEncryptionStandardProvider _provider;
public PasswordHasher(AdvancedEncryptionStandardProvider provider)
{
this._provider = provider;
}
public string HashPassword(string password)
{
// Do no hashing
return this._provider.Encrypt(password);
}
public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
// Throw an error if any of our passwords are null
ThrowIf.ArgumentIsNull(() => hashedPassword, () => providedPassword);
// Just check if the two values are the same
if (hashedPassword.Equals(this.HashPassword(providedPassword)))
return PasswordVerificationResult.Success;
// Fallback
return PasswordVerificationResult.Failed;
}
}
To use this PasswordHasher, you invoke it like this:
var passwordHasher = new PasswordHasher(new AdvancedEncryptionStandardProvider(ConfigurationManager.AppSettings["as:key"], ConfigurationManager.AppSettings["as:secret"]));
This seems to satisfy my conditions. Let me know if there are security risks please!
I have a number of controllers with SessionStateBehavior.ReadOnly set on them to enable parallel processing of multiple ajax requests.
But I have noticed that this doesn't stop me from writing to session (unlike SessionStateBehavior.Disabled which throws an exception).
My application uses Microsoft Charting and the chart and image map are generated in response to an ajax request with the chart being stored in session until the image markup is rendered by the browser at which point the image src triggers the browser to request the chart image which is retrieved from session. So there are no issues here with attempting to read from session before its been written.
Everything works fine, I have multiple ajax requests being processed in parallel and my charts are being returned correctly so does it matter that I have declared SessionStateBehavior.ReadOnly when I am writing to session?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using System.Web.UI.DataVisualization.Charting;
using Mdl.Rcm.Web.Areas.Dashboards.Models;
using Mdl.Web.Security;
using Mdl.Persistence.UoW;
using Mdl.Rcm.Business.Dashboards;
using Mdl.Rcm.Business.Dashboards.Models;
using Mdl.Rcm.Web.Areas.Dashboards.Charts;
using Mdl.Rcm.Web.Areas.Dashboards.Charts.OrganisationConnectionsByRole;
using Mdl.Web.Mvc;
namespace Mdl.Rcm.Web.Areas.Dashboards.Controllers
{
/// <summary>
/// Controller for the Organisation Connections By Role chart.
/// </summary>
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
[RedirectingAuthorize(Roles = "Dashboards")]
[Area(IsSiteRoot = false)]
public class ChartOrganisationConnectionsByRoleController : Controller
{
private readonly IRelationshipAndRiskService relationshipAndRiskService;
private readonly IConfigurationService configurationService;
private readonly IOrganisationConnectionsByRoleChartBuilder chartBuilder;
private readonly IListService listService;
private BarConfiguration barConfiguration;
private const string TempDataKey = "OrganisationConnectionsByRoleData";
public ChartOrganisationConnectionsByRoleController(IOrganisationConnectionsByRoleChart organisationConnectionsByRoleChart, IRelationshipAndRiskService relationshipAndRiskService, IConfigurationService configurationService, IOrganisationConnectionsByRoleChartBuilder chartBuilder, IListService listService)
{
this.relationshipAndRiskService = relationshipAndRiskService;
this.configurationService = configurationService;
this.chartBuilder = chartBuilder;
this.listService = listService;
}
/// <summary>
/// Standard Organisation Connections by Role component loader
/// </summary>
/// <param name="listId">The list id.</param>
/// <param name="degree">The active degree.</param>
/// <param name="barIndex">Index of the active bar.</param>
/// <returns></returns>
[HandleAjaxError]
public ActionResult Load(int listId, int degree, int barIndex)
{
using (UnitOfWork.Start("Analysis"))
{
// Get the data
var relationshipPlanningData = GetChartDataForInitialLoadParentComponent(listId);
var connectionsFound = relationshipPlanningData.SeriesModels.Count > 0;
var listName = listService.GetListName(listId).Name;
var information = new InformationModel(degree, true) { ConnectionsFound = connectionsFound, NumberOfOrganisationsInList = relationshipPlanningData.TotalNumberOfOrganisations, ListName = listName };
return PartialView("OrganisationConnectionsByRoleComponent", new OrganisationConnectionsByRoleComponentModel { ListId = listId, ActiveDegree = degree, ActiveBarIndex = barIndex, BarConfiguration = configurationService.GetBarConfiguration(), ConnectionsFound = connectionsFound, Information = information});
}
}
/// <summary>
/// Creates the Connections by Role chart and stores it in Session then returns the chart map.
/// The chart image map is always created first, the chart is created as part of the process of creating the map.
/// </summary>
/// <returns></returns>
public ActionResult Chart(Guid chartId, int listId)
{
using (UnitOfWork.Start("Analysis"))
{
barConfiguration = configurationService.GetBarConfiguration();
var relationshipPlanningData = GetChartDataForInitialLoadChart();
if (relationshipPlanningData.SeriesModels.Count == 0)
{
return PartialView("InfoMessage", "No connections found");
}
// Set up the chart
return GenerateChart(relationshipPlanningData, listId, chartId);
}
}
private ActionResult GenerateChart(OrganisationConnectionsByRoleData relationshipPlanningData, int listId, Guid chartId)
{
var chartAndXPoints = chartBuilder.BuildChart(2, relationshipPlanningData, barConfiguration, SetActiveBarIndex(-1), listId);
// Store the chart in session for retrieval by the browser as the src on an image tag.
ChartSession.GenerateChartToSession(chartId, chartAndXPoints.Chart, Session);
// Get y data for use client side
var yPointsDataView = GetYPointsDataView(relationshipPlanningData);
// Get x co-ordinates for use client side. Must be done after the chart has been generated to session.
var xPointsView = GetXPointsView(chartAndXPoints.XPoints);
// Render the image tag and image map
return this.Chart(chartAndXPoints.Chart, xPointsView + yPointsDataView, chartId, "ConnectionsByRoleImage");
}
/// <summary>
/// Gets the chart data for use by the main component.
/// </summary>
/// <param name="listId">The list id.</param>
/// <returns></returns>
private OrganisationConnectionsByRoleData GetChartDataForInitialLoadParentComponent(int listId)
{
// This is the call from the load action so get the data and store it for use by the chart action to save the performance hit
var data = relationshipAndRiskService.GetOrganisationConnectionsByRoleChartData(listId);
TempData[TempDataKey] = data;
return data;
}
/// <summary>
/// Gets the chart data for use by the main component chart.
/// </summary>
/// <returns></returns>
private OrganisationConnectionsByRoleData GetChartDataForInitialLoadChart()
{
// This call is from the chart action so use the data that was retreived on the load action
return (OrganisationConnectionsByRoleData)TempData[TempDataKey];
}
/// <summary>
/// Return the Connections By Role chart from session.
/// </summary>
/// <returns></returns>
public ActionResult ConnectionsByRoleImage(Guid chartId)
{
var chart = ChartSession.GetChartFromSession(chartId, Session);
return File(chart, "image");
}
/// <summary>
/// Return the Connections By Role chart from session.
/// </summary>
/// <param name="listId">The list id.</param>
/// <param name="degree">The active degree.</param>
/// <param name="barIndex">Index of the active bar.</param>
/// <returns></returns>
public ActionResult ConnectionsByRoleActive(int listId, int degree, int barIndex)
{
using (UnitOfWork.Start("Analysis"))
{
barConfiguration = configurationService.GetBarConfiguration();
// Get the data
var relationshipPlanningData = relationshipAndRiskService.GetOrganisationConnectionsByRoleChartData(listId);
if (relationshipPlanningData.SeriesModels.Count == 0)
{
return PartialView("InfoMessage", "No connections found");
}
// Set up the chart
var chartAndXPoints = chartBuilder.BuildChart(SetActiveDegree(degree), relationshipPlanningData, barConfiguration, SetActiveBarIndex(-1), listId);
var ms = new MemoryStream();
chartAndXPoints.Chart.SaveImage(ms, ChartImageFormat.Png);
return File(ms.ToArray(), "image");
}
}
/// <summary>
/// Gets the graph X points and render them as a javascript object for use by the view.
/// </summary>
/// <param name="xPoints">The x points.</param>
/// <returns></returns>
private string GetXPointsView(List<float> xPoints)
{
var model = new XPointsModel
{
ChartName = "Connections By Role",
Points = xPoints
};
return this.ViewAsString("XPoints", model);
}
/// <summary>
/// Gets the Y points data and render them as a javascript object for use by the view.
/// </summary>
/// <param name="relationshipPlanningData">The relationship planning data.</param>
/// <returns></returns>
private string GetYPointsDataView(OrganisationConnectionsByRoleData relationshipPlanningData)
{
var degree1DataPoints = relationshipPlanningData.SeriesModels[0].DataPoints.Select(p => p.Y).ToList();
var degree2DataPoints = relationshipPlanningData.SeriesModels[1].DataPoints.Select(p => p.Y).ToList();
var model = new YPointsDegree1And2Model
{
ChartName = "Connections By Role",
Degree1Data = degree1DataPoints,
Degree2Data = degree2DataPoints
};
return this.ViewAsString("YPointsDegree1And2", model);
}
private int SetActiveBarIndex(int barIndex)
{
if (barIndex == -1)
{
barIndex = barConfiguration.Bars.First(b => b.IsDefaultActive).Index;
}
return barIndex;
}
private static int SetActiveDegree(int degree)
{
if (degree == -1)
{
degree = 2;
}
return degree;
}
}
}
public class ChartSession
{
public static byte[] GetChartFromSession(Guid chartId, HttpSessionStateBase session)
{
// Get the chart from session
var data = session[chartId.ToString()] as byte[];
// Clear the session
session[chartId.ToString()] = null;
return data;
}
public static void GenerateChartToSession(Guid chartId, Chart chart, HttpSessionStateBase session)
{
var ms = new MemoryStream();
chart.SaveImage(ms, ChartImageFormat.Png);
session[chartId.ToString()] = ms.ToArray();
}
SessionStateBehavior only tells ASP.NET what locks to put on the Session
See this question: Controller SessionStateBehavior is ReadOnly and I can update Session Variable