Skip to content

Commit

Permalink
porting changes to support VendorCredentials (which are used for auth…
Browse files Browse the repository at this point in the history
…orization IPN requests)
  • Loading branch information
fschwiet committed Nov 6, 2013
1 parent ed4bafd commit 9375966
Show file tree
Hide file tree
Showing 22 changed files with 421 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/KeyHub.Common/KeyHub.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Reflection.Context" />
Expand Down
11 changes: 11 additions & 0 deletions src/KeyHub.Common/Utils/SymmetricEncryption.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
Expand All @@ -18,6 +19,16 @@ namespace KeyHub.Common.Utils
/// </summary>
public class SymmetricEncryption
{
public static byte[] EncryptForDatabase(byte[] data)
{
return Encrypt(data, ConfigurationManager.AppSettings["DatabaseEncryptionKey"]);
}

public static byte[] DecryptForDatabase(byte[] data)
{
return Decrypt(data, ConfigurationManager.AppSettings["DatabaseEncryptionKey"]);
}

public static byte[] Encrypt(byte[] data, string privateKey)
{
// We hash the private key string to ensure we have a key with the correct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public VendorConfiguration()
m.MapInheritedProperties();
m.ToTable("Vendors");
});

HasMany(x => x.VendorCredentials).WithRequired(x => x.Vendor);
}

public void AddConfiguration(System.Data.Entity.ModelConfiguration.Configuration.ConfigurationRegistrar registrar)
Expand Down
3 changes: 3 additions & 0 deletions src/KeyHub.Data/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public DataContext()
: base(Constants.ConnectionStringName)
{
this.Vendors = new FilteredDbSet<Vendor>(this);
this.VendorCredentials = new FilteredDbSet<VendorCredential>(this);
this.SKUs = new FilteredDbSet<SKU>(this);
this.Features = new FilteredDbSet<Feature>(this);
this.SkuFeatures = new FilteredDbSet<SkuFeature>(this);
Expand Down Expand Up @@ -89,6 +90,8 @@ public User GetUser(IIdentity identity)

public IDbSet<Vendor> Vendors { get; set; }

public IDbSet<VendorCredential> VendorCredentials { get; set; }

public IDbSet<Customer> Customers { get; set; }

public IDbSet<License> Licenses { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/KeyHub.Data/IDataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public interface IDataContext : IDisposable
IDbSet<TransactionItem> TransactionItems { get; set; }
IDbSet<TransactionIgnoredItem> TransactionIgnoredItems { get; set; }
IDbSet<Vendor> Vendors { get; set; }
IDbSet<VendorCredential> VendorCredentials { get; set; }
IDbSet<Customer> Customers { get; set; }
IDbSet<License> Licenses { get; set; }
IDbSet<Right> Rights { get; set; }
Expand Down
14 changes: 13 additions & 1 deletion src/KeyHub.Data/Migrations/201303260850051_InitialCreate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,19 @@ public override void Up()
.Index(t => t.SkuId)
.Index(t => t.PurchasingCustomerId)
.Index(t => t.OwningCustomerId);


CreateTable(
"dbo.VendorCredentials",
c => new
{
VendorCredentialId = c.Guid(nullable: false, identity: true),
VendorId = c.Guid(nullable: false),
CredentialName = c.String(nullable: false),
CredentialValue = c.Binary(nullable: false)
})
.PrimaryKey(t => t.VendorCredentialId)
.ForeignKey("dbo.Vendors", t => t.VendorId, cascadeDelete: true)
.Index(t => t.VendorId);
}

public override void Down()
Expand Down
2 changes: 1 addition & 1 deletion src/KeyHub.Model/Definition/Application/DomainLicense.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public partial class DomainLicense : IModelItem
public bool AutomaticlyCreated { get; set; }

/// <summary>
/// The private key in bytes, encrypted with KeyHub.Common.SymmetricEncryption
/// The private key in bytes, encrypted with KeyHub.Common.SymmetricEncryption.EncryptForDatabase
/// </summary>
[Required]
[MaxLength(4096)]
Expand Down
2 changes: 1 addition & 1 deletion src/KeyHub.Model/Definition/Application/PrivateKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public partial class PrivateKey
public string DisplayName { get; set; }

/// <summary>
/// The private key in bytes, encrypted with KeyHub.Common.SymmetricEncryption
/// The private key in bytes, encrypted with KeyHub.Common.SymmetricEncryption.EncryptForDatabase
/// </summary>
[Required]
[MaxLength(4096)]
Expand Down
2 changes: 2 additions & 0 deletions src/KeyHub.Model/Definition/Application/Vendor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,7 @@ public class Vendor : RightObject
/// A list of private keys this vendor owns
/// </summary>
public virtual ICollection<PrivateKey> PrivateKeys { get; set; }

public virtual ICollection<VendorCredential> VendorCredentials { get; set; }
}
}
48 changes: 48 additions & 0 deletions src/KeyHub.Model/Definition/Application/VendorCredential.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KeyHub.Model
{
/// <summary>
/// Shared secret used by vendors when POST'ing transactions
/// </summary>
public class VendorCredential
{
/// <summary>
/// Indentifier for the PrivateKey entity.
/// </summary>
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public Guid VendorCredentialId { get; set; }

/// <summary>
/// The vendor this key is owned by.
/// </summary>
[Required]
public Guid VendorId { get; set; }

/// <summary>
/// The vendor this key is owned by.
/// </summary>
[ForeignKey("VendorId")]
public Vendor Vendor { get; set; }


/// <summary>
/// The name of the shared secret (managed by the vendor)
/// </summary>
[Required]
public string CredentialName { get; set; }

/// <summary>
/// The shared secret, encrypted by SymmetricEncryption.EncryptForDatabase
/// </summary>
[Required]
public byte[] CredentialValue { get; set; }
}
}
1 change: 1 addition & 0 deletions src/KeyHub.Model/KeyHub.Model.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<Compile Include="Definition\Membership\Rights\IRight.cs" />
<Compile Include="Definition\Membership\Rights\VendorAdmin.cs" />
<Compile Include="Definition\Membership\Rights\VendorReporting.cs" />
<Compile Include="Definition\Application\VendorCredential.cs" />
<Compile Include="IModelItem.cs" />
<Compile Include="Logic\Application\CustomerApp.cs" />
<Compile Include="Logic\Application\DomainLicense.cs" />
Expand Down
5 changes: 2 additions & 3 deletions src/KeyHub.Model/Logic/Application/PrivateKey.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
Expand All @@ -22,7 +21,7 @@ public void SetKeyBytes()
try
{
var privateKeyBytes = r.ExportCspBlob(true);
this.KeyBytes = SymmetricEncryption.Encrypt(privateKeyBytes, ConfigurationManager.AppSettings["DatabaseEncryptionKey"]);
this.KeyBytes = SymmetricEncryption.EncryptForDatabase(privateKeyBytes);
}
finally{
r.PersistKeyInCsp = false;
Expand All @@ -39,7 +38,7 @@ public string GetPublicKeyXmlString()
{
try
{
var privateKey = SymmetricEncryption.Decrypt(KeyBytes, ConfigurationManager.AppSettings["DatabaseEncryptionKey"]);
var privateKey = SymmetricEncryption.DecryptForDatabase(KeyBytes);

r.ImportCspBlob(privateKey);
return r.ToXmlString(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private static string Serialize(IEnumerable<DomainValidationResult> domainValida
/// <returns>Encrypted text</returns>
public static byte[] SignData(string text, byte[] keyBytes)
{
byte[] decryptedKey = SymmetricEncryption.Decrypt(keyBytes, ConfigurationManager.AppSettings["DatabaseEncryptionKey"]);
byte[] decryptedKey = SymmetricEncryption.DecryptForDatabase(keyBytes);

using (var r = new RSACryptoServiceProvider(2048, new CspParameters() { Flags = CspProviderFlags.NoPrompt | CspProviderFlags.CreateEphemeralKey }))
{
Expand Down
31 changes: 26 additions & 5 deletions src/KeyHub.Web/Api/Controllers/TransactionByIpnController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Data.Entity;
using System.Text;
using KeyHub.Common.Collections;
using System;
using System.Collections.Generic;
Expand All @@ -9,6 +10,7 @@
using System.Web.Http;
using System.Xml;
using KeyHub.Common.Extensions;
using KeyHub.Common.Utils;
using KeyHub.Core.Mail;
using KeyHub.Data;
using KeyHub.Web.Api.Controllers.LicenseValidation;
Expand Down Expand Up @@ -39,20 +41,39 @@ public TransactionByIpnController(IDataContextFactory dataContextFactory, IMailS
/// <param name="postedData"></param>
public HttpResponseMessage PostTransactionByIpn([FromUri]string id, [FromBody]FormDataCollection postedData)
{
string vendor = id;
var vendorId = Guid.Parse(id);
var txn = new Transaction();
var d = postedData.ReadAsNameValueCollection();

//To calculate 'handshake', run 'md5 -s [password]', then 'md5 -s [email protected][Last MD5 result]'
if (!"ff35a320762dcec799d9c0bb9831577c".Equals(d.Pluck("handshake",null), StringComparison.OrdinalIgnoreCase)) throw new Exception("Invalid handshake provided");
string handshakeParameter = d.Pluck("handshake",null);
if (handshakeParameter == null)
throw new Exception("Missing parameter 'handshake'.");

using (var dataContext = dataContextFactory.Create())
{
var vendor =
dataContext.Vendors.Where(v => v.ObjectId == vendorId)
.Include(v => v.VendorCredentials)
.FirstOrDefault();

if (vendor == null)
throw new Exception("Could not find vendor with id: " + vendorId);

string[] vendorCredentials = vendor.VendorCredentials.Select(
c => Encoding.UTF8.GetString(SymmetricEncryption.DecryptForDatabase(c.CredentialValue)).ToLower()).ToArray();

if (!vendorCredentials.Contains(handshakeParameter.ToLower()))
throw new Exception("Invalid handshake provided");
}

string txn_id = d.Pluck("txn_id");
//TODO: We must ignore duplicate POSTs with the same txn_id - all POSTs will contain the same information

if (!"Completed".Equals(d.Pluck("payment_status"), StringComparison.OrdinalIgnoreCase)) throw new Exception("Only completed transactions should be sent to this URL");

//var txn = new Transaction();
txn.VendorId = Guid.Parse(vendor);
txn.VendorId = vendorId;
txn.ExternalTransactionId = txn_id;
txn.PaymentDate = ConvertPayPalDateTime(d.Pluck("payment_date"));
txn.PayerEmail = d.Pluck("payer_email");
Expand Down Expand Up @@ -101,7 +122,7 @@ public HttpResponseMessage PostTransactionByIpn([FromUri]string id, [FromBody]Fo
txn.Other = d;

//All transactions go through TransactionController
base.ProcessTransaction(txn.ToTransactionRequest(dataContextFactory), User.Identity);
base.ProcessTransaction(txn.ToTransactionRequest(dataContextFactory), new [] { vendorId});

return new HttpResponseMessage(HttpStatusCode.OK);
}
Expand Down
6 changes: 4 additions & 2 deletions src/KeyHub.Web/Controllers/VendorController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ public ActionResult Details(Guid key)
using (var context = dataContextFactory.CreateByUser())
{
//Eager loading Vendor
var vendorQuery = (from v in context.Vendors where v.ObjectId == key select v).Include(x => x.Country);
var vendorQuery = (from v in context.Vendors where v.ObjectId == key select v).Include(x => x.Country).Include(x => x.VendorCredentials);
var vendor = vendorQuery.FirstOrDefault();

VendorDetailsViewModel viewModel = new VendorDetailsViewModel(vendorQuery.FirstOrDefault());
VendorDetailsViewModel viewModel = new VendorDetailsViewModel(vendor);
viewModel.Vendor.VenderCredentials = vendor.VendorCredentials;

return View(viewModel);
}
Expand Down
Loading

0 comments on commit 9375966

Please sign in to comment.