Simple way to encrypt data in winrt - encryption

I am trying to encrypt a string with Windows RT. Before it was possible to use the ProtectData in the system.security namespace but that does not exist in WinRT. I tried to use the following code but it does not work.
public static async Task<string> EncryptSting(string data)
{
DataProtectionProvider provider = new DataProtectionProvider();
IBuffer unprotectedData = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
//crashes here
IBuffer protectedData = await provider.ProtectAsync(unprotectedData);
return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, protectedData);
}
public static async Task<string> DecryptString(string data)
{
DataProtectionProvider provider = new DataProtectionProvider();
IBuffer inputData = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
//crashes here
IBuffer unprotectedData = await provider.UnprotectAsync(inputData);
return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, unprotectedData);
}
Edit: The execption is
The supplied handle is invalid. (Exception from HRESULT: 0x80090026)
and it occurs on the 3rd line when encrypting and decrypting

According to the documentation, the constructor you're using can only be used for decryption, not for encryption:
Constructor used for decryption operations. Use this constructor before calling the UnprotectAsync or UnprotectStreamAsync methods.
For encryption, you must use the other constructor, which specifies if the data should be encrypted for the local machine, current user, specific user, etc.
I don't know why it doesn't work for decryption in your case, but if encryption doesn't work, I'm not sure what you're trying to decrypt...

Try to do the following:
public static async Task<string> EncryptSting(string data)
{
DataProtectionProvider provider = new DataProtectionProvider("LOCAL=user");
...
...
}
Cheers!

Related

App Service to EntityFramework using MSI

I'm trying to retrofit MSI to an existing app.
The original app's DbContext used only a Constructor that found a ConnectionString by the same name in the web.config.
I've modified it to use a DbConnectionFactory to inject an AccessToken.
public class AppCoreDbContext : DbContext {
public AppCoreDbContext() : this("AppCoreDbContext")
{
}
public AppCoreDbContext(string connectionStringOrName) : base( OpenDbConnectionBuilder.Create(connectionStringOrName).Result, true)
{
}
...etc...
}
The class that it is invoking looks like:
public static class OpenDbConnectionBuilder
{
public static async Task<DbConnection> CreateAsync(string connectionStringName)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var dbConnection = DbProviderFactories
.GetFactory(connectionStringSettings.ProviderName)
.CreateConnection();
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
await AttachAccessTokenToDbConnection(dbConnection);
// Think DbContext will open it when first used.
//await dbConnection.OpenAsync();
return dbConnection;
}
static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
{
SqlConnection sqlConnection = dbConnection as SqlConnection;
if (sqlConnection == null)
{
return;
}
string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
if (string.IsNullOrEmpty(msiEndpoint))
{
return;
}
var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
if (string.IsNullOrEmpty(msiSecret))
{
return;
}
string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
sqlConnection.AccessToken = accessToken;
}
}
Which invokes
// Refer to: https://winterdom.com/2017/10/19/azure-sql-auth-with-msi
public static class AppCoreDbContextMSITokenFactory
{
private const String azureSqlResource = "https://database.windows.net/";
public static async Task<String> GetAzureSqlResourceTokenAsync()
{
var provider = new AzureServiceTokenProvider();
var result = await provider.GetAccessTokenAsync(azureSqlResource);
return result;
}
}
The result of the above is that when tracking it with a debugger, it gets to
var result = await provider.GetAccessTokenAsync(azureSqlResource);
then hangs for ever.
Note: I'm working on a personal machine, not joined to the organisation domain -- but my personal MSA has been invited to the organisation's domain.
Admittedly, I've taken a hiatus from development for a couple of years, and the hang is probably due to having made a mistake around await (always been rough on understanding that implicitly)... but while trying to figure that out, and the documentation is pretty sparse, would appreciate feedback as to whether the above was the intended approach for using MSI.
I'm wondering:
When deploying to Azure, we can tell the ARM to create the Identity -- when developing, how do we tell the local machine to use MSI?
If on the dev machine the connection string is to a local db, and I create and add the token anyway, will it ignore it, or raise an exception.
This is a bit beyond the scope of discussing MSI, but I've never before created a dbConnection to use within a DbContext. Does anyone know the pros/cons of the DbContext 'owning' the connection? I'm assuming that it would be wiser to own & close the connection when the dbcontext is closed.
Basically...this is all new, so would appreciate any advice on getting this working -- the concept of being able to deploy without secrets would be awesome and would really like to get this demo working.
Thanks very much!
Hello user9314395: Managed Service Identity only works with resources running on Azure. While we don't support the local development scenario, you might consider looking into using the following (preview) library: https://learn.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

Where to store tokens in a xamarin.form application

I have the class below that will be used in a xamarin.forms mobile application
to retrieve the token generated by OAuth(webapi). Once this is generated I need to store
in a place where I can access it again and not generating this all the time.
Where is the best place to store this in the Pcl? I will also want to be able to remove this once
the user logs off.
class LoginService
{
public async Task Login(string username, string password)
{
HttpWebRequest request = new HttpWebRequest(new Uri(String.Format("{0}Token", Constants.BaseAddress)));
request.Method = "POST";
string postString = String.Format("username={0}&password={1}&grant_type=password",
HttpUtility.HtmlEncode(username), HttpUtility.HtmlEncode(password));
byte[] bytes = Encoding.UTF8.GetBytes(postString);
using (Stream requestStream = await request.GetRequestStreamAsync())
{
requestStream.Write(bytes, 0, bytes.Length);
}
try
{
HttpWebResponse httpResponse = (HttpWebResponse)(await request.GetResponseAsync());
string json;
using (Stream responseStream = httpResponse.GetResponseStream())
{
json = new StreamReader(responseStream).ReadToEnd();
}
TokenResponseModel tokenResponse = JsonConvert.DeserializeObject(json);
return tokenResponse.AccessToken;
}
catch (Exception ex)
{
throw new SecurityException("Bad credentials", ex);
}
}
}
Token(s) being sensitive information, I would recommend storing them in a secure manner. Secure storage is available through Keychain services in iOS, and the KeyStore class in Android. Xamarin has a very good article on how to do that using Xamarin.Auth.
Other options available are:
BlobCache.Secure in Akavache
SecureStorage
Secure storage in XLabs
Just an update for anyone searching, as things have changed since this post was created. It is not advised to use the following any more:
Application.Current.Properties
To securely store things like access tokens etc you can use the Xamarin.Essentials SecureStorage static class.
Just add the Xamarin.Essentials nuget package if you don't already have it and use it like so:
using Xamarin.Essentials;
.
.
.
await SecureStorage.SetAsync("someKey", "someValue");
var myValue = await SecureStorage.GetAsync("someKey");
you also have the option to
SecureStorage.Remove("someKey");
//or
SecureStorage.RemoveAll();
Refer this for more documentation
Forms has a built in Properties dictionary where you can store small bits of persistent data.
Application.Current.Properties ["token"] = myToken;

When calling AcquireTokenByRefreshToken on the AuthenticationContext instance with Microsoft.IdentityModel.Clients.ActiveDirectory?

I am developing a multi-tenant application registered on my Azure AD that consumes Office 365 apis, Graph API etc.
I followed this Microsoft sample to build my work which uses ADAL .NET library and OpenIdConnect: Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.19.0.0
In ADAL.NET, we use an AuthenticationContext instance with a custom inherited class for the TokenCache (see code the sample code here).
For each request to the authorized resources, depending on the API, we invoke one of these methods (see code below) to get the auth_token that will be put in the request Bearer parameter. Is it the correct way to do it?
We never make use of the method AcquireTokenByRefreshTokenAsync, does it mean that our application never uses the refresh_token? Does it mean that our user will have to relog after one hour? Should we implement a kind of refreshing procedure with AcquireTokenByRefreshTokenAsync in the catch statement? Can it be made without prompting anything to the end-user?
REMARK: I posted a question regarding OpenIdConnect authentication ticket lifetime. To me these two questions are unrelated but they may be.
string signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string userObjectId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
string tenantId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
public async Task<string> AcquireOutlook365TokenAsync()
{
AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", SettingsHelper.AuthorizationUri, tenantId), new ADALTokenCache(signInUserId));
try
{
var result = await authContext.AcquireTokenSilentAsync(#"https://outlook.office365.com/",
new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey),
new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
catch (AdalException exception)
{
//handle token acquisition failure
if (exception.ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
authContext.TokenCache.Clear();
}
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
}
public async Task<string> AcquireAzureGraphTokenAsync()
{
AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", SettingsHelper.AuthorizationUri, tenantId), new ADALTokenCache(signInUserId));
try
{
var result = await authContext.AcquireTokenSilentAsync(#"https://graph.windows.net/",
new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey),
new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
catch (AdalException exception)
{
//Same as other method
}
}
ADAL uses the stored refresh tokens automatically and transparently, you aren't required to perform any explicit action. AcquireTOkenByRefreshToken is in the ADAL surface for legacy reasons, and has been removed from version 3.x. More background at http://www.cloudidentity.com/blog/2015/08/13/adal-3-didnt-return-refresh-tokens-for-5-months-and-nobody-noticed/

ResetPassword Token How and where is it stored?

I've been trying to understand how the reset password & account confirmation works in ASP.NET Identity. I'd just like to know if the Tokens are being stored and if so, where?
The links I receive when I'm using the password reset feature look something like this
http://localhost:1470/Account/ResetPassword?userId=a8b1389c-df93-4dfc-b463-541507c1a4bc&code=yhUegXIM9SZBpPVbBtv22kg7NO7F96B8MJi9MryAadUY5XYjz8srVkS5UL8Lx%2BLPYTU6a6jhqOrzMUkkMyPbEHPY3Ul6%2B%2F0s0qQvtM%2FLLII3s29FgkcK0OnjX46Bmj9JlFCUx53rOH%2FXMacwnKDzoJ1rbrUyypZiJXloIE50Q6iPuMTUHbX9O%2B3JMZtCVXjhhsHLkTOn9IVoN6uVAOMWNQ%3D%3D
My guess is that the tokens are stored in the link itself since I cannot find any trace of it anywhere else. Maybe someone knows for sure?
As I mentioned in the comment
"Tokens are generated using the SecurityStamp and validating against the SecurityStamp and not storing anywhere in database or local file storage. If you update the SecurityStamp, then previous tokens are no longer valid."
#DSR is correct but I would like to add some information to this as well.
If you have set up a Web project with Individual User Accounts go to:
App_Start -> IdentityConfig.cs
There you will see code like this:
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
The description for DataProtectorTokenProvider<TUser, TKey> gives the information:
Represents a token provider that uses an IDataProtector to generate
encrypted tokens based off of the security stamp.
https://learn.microsoft.com/en-us/previous-versions/aspnet/dn613280(v%3dvs.108)
We can however try to dig a bit deeper how it really works. The token verification will fail if different Application Pool Identities are used for creating and validating a token on a single server. This points to that the actual protection mechanism would look something like this:
System.Security.Cryptography.ProtectedData.Protect(userData, entropy, DataProtectionScope.CurrentUser);
Given that it works if all sites use the same Application Pool Identity points to this as well. Could also be DataProtectionProvider with protectionDescriptor "LOCAL=user". It should have worked with different Application Pool Identities if LOCAL=machine was set.
new DataProtectionProvider("LOCAL=user")
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.dataprotector?view=netframework-4.7.2
https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider
dataProtectionProvider is of type IDataProtectionProvider.
It is injected in Startup.Auth.cs like this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
CreatePerOwinContext is located in the assembly Microsoft.AspNet.Identity.Owin -> AppBuilderExtensions.cs. Both ASP.NET Identity and ASP.NET Core Identity are open source and can be viewed at GitHub.
public static IAppBuilder CreatePerOwinContext<T>(this IAppBuilder app,
Func<IdentityFactoryOptions<T>, IOwinContext, T> createCallback,
Action<IdentityFactoryOptions<T>, T> disposeCallback) where T : class, IDisposable
{
if (app == null)
{
throw new ArgumentNullException("app");
}
if (createCallback == null)
{
throw new ArgumentNullException("createCallback");
}
if (disposeCallback == null)
{
throw new ArgumentNullException("disposeCallback");
}
app.Use(typeof (IdentityFactoryMiddleware<T, IdentityFactoryOptions<T>>),
new IdentityFactoryOptions<T>
{
DataProtectionProvider = app.GetDataProtectionProvider(),
Provider = new IdentityFactoryProvider<T>
{
OnCreate = createCallback,
OnDispose = disposeCallback
}
});
return app;
}
https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Owin/Extensions/AppBuilderExtensions.cs
https://archive.codeplex.com/?p=aspnetidentity#src/Microsoft.AspNet.Identity.Owin/Extensions/AppBuilderExtensions.cs
app.GetDataProtectionProvider() is in turn located in assembly Microsoft.Owin.Security that is also Open Source.
public static IDataProtectionProvider GetDataProtectionProvider(this IAppBuilder app)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
object value;
if (app.Properties.TryGetValue("security.DataProtectionProvider", out value))
{
var del = value as DataProtectionProviderDelegate;
if (del != null)
{
return new CallDataProtectionProvider(del);
}
}
return null;
}
https://github.com/aspnet/AspNetKatana/blob/release/src/Microsoft.Owin.Security/DataProtection/AppBuilderExtensions.cs
We can also see that CreateDataProtector has a fallback to the implementation DpapiDataProtectionProvider.
private static IDataProtectionProvider FallbackDataProtectionProvider(IAppBuilder app)
{
return new DpapiDataProtectionProvider(GetAppName(app));
}
When reading about DpapiDataProtectionProvider(DPAPI stands for Data Protection Application Programming Interface) the description says:
Used to provide the data protection services that are derived from the
Data Protection API. It is the best choice of data protection when you
application is not hosted by ASP.NET and all processes are running as
the same domain identity.
The Create method purposes are described as:
Additional entropy used to ensure protected data may only be
unprotected for the correct purposes.
The protector class itself then looks like this:
using System.Security.Cryptography;
namespace Microsoft.Owin.Security.DataProtection
{
internal class DpapiDataProtector : IDataProtector
{
private readonly System.Security.Cryptography.DpapiDataProtector _protector;
public DpapiDataProtector(string appName, string[] purposes)
{
_protector = new System.Security.Cryptography.DpapiDataProtector(appName, "Microsoft.Owin.Security.IDataProtector", purposes)
{
Scope = DataProtectionScope.CurrentUser
};
}
public byte[] Protect(byte[] userData)
{
return _protector.Protect(userData);
}
public byte[] Unprotect(byte[] protectedData)
{
return _protector.Unprotect(protectedData);
}
}
}
https://learn.microsoft.com/en-us/previous-versions/aspnet/dn253784(v%3dvs.113)

Re-inventing my authentication strategy with ASP.NET

Currently, I use custom written authentication code for my site, which is built on .NET. I didn't take the standard Forms Auth route, as all the examples I could find were tightly integrated with WebForms, which I do not use. For all intents and purposes, I have all static HTML, and any logic is done through Javascript and web service calls. Things like logging in, logging off, and creating a new account are done without even leaving the page.
Here's how it works now: In the database, I have a User ID, a Security ID, and a Session ID. All three are UUIDs, and the first two never change. Each time the user logs on, I check the user table for a row that matches that username and hashed password, and I update the Session ID to a new UUID. I then create a cookie that's a serialized representation of all three UUIDs. In any secure web service calls, I deserialize that cookie that make sure there's a row in the users table with those 3 UUIDs. It's a fairly simple system and works well, however I don't really like the fact that a user can only be logged on with one client at a time. It's going to cause issues when I create mobile and tablet apps, and already creates issues if they have multiple computers or web browsers. For this reason, I'm thinking about throwing away this system and going with something new. Since I wrote it years ago, I figure there might be something much more recommended.
I've been reading up on the FormsAuthentication class in the .NET Framework, which handles auth cookies, and runs as an HttpModule to validate each request. I'm wondering if I can take advantage of this in my new design.
It looks like cookies are stateless, and sessions don't have to be tracked within the database. This is done through the fact that cookies are encrypted with a private key on the server, that can also be shared across a cluster of web servers. If I do something like:
FormsAuthentication.SetAuthCookie("Bob", true);
Then in later requests, I can be assured that Bob is indeed a valid user as a cookie would be very difficult if not impossible to forge.
Would I be wise to use the FormsAuthentication class to replace my current authentication model with? Rather than have a Session ID column in the database, I'd rely on encrypted cookies to represent valid sessions.
Are there third party/open source .NET authentication frameworks that might work better for my architecture?
Will this authentication mechanism cause any grief with code running on mobile and tablet clients, such as an iPhone app or Windows 8 Surface app? I would assume this would work, as long as these apps could handle cookies. Thanks!
Since I didn't get any responses, I decided to take a shot at this myself. First, I found an open source project that implements session cookies in an algorithm agnostic way. I used this as a starting point to implement a similar handler.
One issue I had with the built in ASP.NET implementation, which is a similar restriction in the AppHarbor implementation, is sessions are only keyed by a string username. I wanted to be able to store arbitrary data to identify a user, such as their UUID in the database as well as their logon name. As much of my existing code assumes this data is available in the cookie, it would take a lot of refactoring if this data were no longer available. Plus, I like the idea of being able to store basic user information without having to hit the database.
Another issue with the AppHarbor project, as pointed out in the this open issue, is the encryption algorithm isn't verified. This is not exactly true, as AppHarbor is algorithm agnostic, however it was requested that the sample project should show how to use PBKDF2. For that reason, I decided to use this algorithm (implemented in the .NET Framework through the Rfc2898DeriveBytes class) in my code.
Here's what I was able to come up with. It's meant as a starting point for someone looking to implement their own session management, so feel free to use it for whatever purpose you see fit.
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Web;
namespace AuthTest
{
[Serializable]
public class AuthIdentity : IIdentity
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public AuthIdentity() { }
public AuthIdentity(Guid id, string name)
{
Id = id;
Name = name;
}
public string AuthenticationType
{
get { return "CookieAuth"; }
}
public bool IsAuthenticated
{
get { return Id != Guid.Empty; }
}
}
[Serializable]
public class AuthToken : IPrincipal
{
public IIdentity Identity { get; set; }
public bool IsInRole(string role)
{
return false;
}
}
public class AuthModule : IHttpModule
{
static string COOKIE_NAME = "AuthCookie";
//Note: Change these two keys to something else (VALIDATION_KEY is 72 bytes, ENCRYPTION_KEY is 64 bytes)
static string VALIDATION_KEY = #"MkMvk1JL/ghytaERtl6A25iTf/ABC2MgPsFlEbASJ5SX4DiqnDN3CjV7HXQI0GBOGyA8nHjSVaAJXNEqrKmOMg==";
static string ENCRYPTION_KEY = #"QQJYW8ditkzaUFppCJj+DcCTc/H9TpnSRQrLGBQkhy/jnYjqF8iR6do9NvI8PL8MmniFvdc21sTuKkw94jxID4cDYoqr7JDj";
static byte[] key;
static byte[] iv;
static byte[] valKey;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnAuthenticateRequest;
context.EndRequest += OnEndRequest;
byte[] bytes = Convert.FromBase64String(ENCRYPTION_KEY); //72 bytes (8 for salt, 64 for key)
byte[] salt = bytes.Take(8).ToArray();
byte[] pw = bytes.Skip(8).ToArray();
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pw, salt, 1000);
key = k1.GetBytes(16);
iv = k1.GetBytes(8);
valKey = Convert.FromBase64String(VALIDATION_KEY); //64 byte validation key to prevent tampering
}
public static void SetCookie(AuthIdentity token, bool rememberMe = false)
{
//Base64 encode token
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, token);
byte[] buffer = stream.GetBuffer();
byte[] encryptedBytes = EncryptCookie(buffer);
string str = Convert.ToBase64String(encryptedBytes);
var cookie = new HttpCookie(COOKIE_NAME, str);
cookie.HttpOnly = true;
if (rememberMe)
{
cookie.Expires = DateTime.Today.AddDays(100);
}
HttpContext.Current.Response.Cookies.Add(cookie);
}
public static void Logout()
{
HttpContext.Current.Response.Cookies.Remove(COOKIE_NAME);
HttpContext.Current.Response.Cookies.Add(new HttpCookie(COOKIE_NAME, "")
{
Expires = DateTime.Today.AddDays(-1)
});
}
private static byte[] EncryptCookie(byte[] rawBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, des.CreateEncryptor(), CryptoStreamMode.Write);
encrypt.Write(rawBytes, 0, rawBytes.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] encBytes = encryptionStream.ToArray();
//Add validation hash (compute hash on unencrypted data)
HMACSHA256 hmac = new HMACSHA256(valKey);
byte[] hash = hmac.ComputeHash(rawBytes);
//Combine encrypted bytes and validation hash
byte[] ret = encBytes.Concat<byte>(hash).ToArray();
return ret;
}
private static byte[] DecryptCookie(byte[] encBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
HMACSHA256 hmac = new HMACSHA256(valKey);
int valSize = hmac.HashSize / 8;
int msgLength = encBytes.Length - valSize;
byte[] message = new byte[msgLength];
byte[] valBytes = new byte[valSize];
Buffer.BlockCopy(encBytes, 0, message, 0, msgLength);
Buffer.BlockCopy(encBytes, msgLength, valBytes, 0, valSize);
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, des.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(message, 0, msgLength);
decrypt.Flush();
byte[] decMessage = decryptionStreamBacking.ToArray();
//Verify key matches
byte[] hash = hmac.ComputeHash(decMessage);
if (valBytes.SequenceEqual(hash))
{
return decMessage;
}
throw new SecurityException("Auth Cookie appears to have been tampered with!");
}
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var cookie = context.Request.Cookies[COOKIE_NAME];
if (cookie != null && cookie.Value.Length > 0)
{
try
{
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
var bytes = Convert.FromBase64String(cookie.Value);
var decBytes = DecryptCookie(bytes);
stream.Write(decBytes, 0, decBytes.Length);
stream.Seek(0, SeekOrigin.Begin);
AuthIdentity auth = formatter.Deserialize(stream) as AuthIdentity;
AuthToken token = new AuthToken() { Identity = auth };
context.User = token;
//Renew the cookie for another 100 days (TODO: Should only renew if cookie was originally set to persist)
context.Response.Cookies[COOKIE_NAME].Value = cookie.Value;
context.Response.Cookies[COOKIE_NAME].Expires = DateTime.Today.AddDays(100);
}
catch { } //Ignore any errors with bad cookies
}
}
private void OnEndRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var response = context.Response;
if (response.Cookies.Keys.Cast<string>().Contains(COOKIE_NAME))
{
response.Cache.SetCacheability(HttpCacheability.NoCache, "Set-Cookie");
}
}
}
}
Also, be sure to include the following module in your web.config file:
<httpModules>
<add name="AuthModule" type="AuthTest.AuthModule" />
</httpModules>
In your code, you can lookup the currently logged on user with:
var id = HttpContext.Current.User.Identity as AuthIdentity;
And set the auth cookie like so:
AuthIdentity token = new AuthIdentity(Guid.NewGuid(), "Mike");
AuthModule.SetCookie(token, false);

Resources