diff options
Diffstat (limited to 'samples')
19 files changed, 818 insertions, 594 deletions
diff --git a/samples/OAuthAuthorizationServer/Code/DataClasses.dbml b/samples/OAuthAuthorizationServer/Code/DataClasses.dbml index 33e6eda..0ef987d 100644 --- a/samples/OAuthAuthorizationServer/Code/DataClasses.dbml +++ b/samples/OAuthAuthorizationServer/Code/DataClasses.dbml @@ -37,4 +37,12 @@ <Column Name="Timestamp" Type="System.DateTime" IsPrimaryKey="true" CanBeNull="false" /> </Type> </Table> + <Table Name="" Member="SymmetricCryptoKeys"> + <Type Name="SymmetricCryptoKey"> + <Column Name="Bucket" Type="System.String" IsPrimaryKey="true" CanBeNull="false" UpdateCheck="Never" /> + <Column Name="Handle" Type="System.String" IsPrimaryKey="true" CanBeNull="false" UpdateCheck="Never" /> + <Column Name="ExpiresUtc" Type="System.DateTime" CanBeNull="false" UpdateCheck="Never" /> + <Column Name="Secret" Type="System.Byte[]" CanBeNull="false" UpdateCheck="Never" /> + </Type> + </Table> </Database>
\ No newline at end of file diff --git a/samples/OAuthAuthorizationServer/Code/DataClasses.dbml.layout b/samples/OAuthAuthorizationServer/Code/DataClasses.dbml.layout index e2982ce..f4de725 100644 --- a/samples/OAuthAuthorizationServer/Code/DataClasses.dbml.layout +++ b/samples/OAuthAuthorizationServer/Code/DataClasses.dbml.layout @@ -40,5 +40,11 @@ <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> </nodes> </associationConnector> + <classShape Id="93df6fa9-cc66-44a9-8885-960b1e670dd7" absoluteBounds="4.125, 6.25, 2, 1.5785953776041666"> + <DataClassMoniker Name="/DataClassesDataContext/SymmetricCryptoKey" /> + <nestedChildShapes> + <elementListCompartment Id="0b486eb8-31a4-4f11-b58f-09540c56319b" absoluteBounds="4.14, 6.71, 1.9700000000000002, 1.0185953776041665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> </nestedChildShapes> </ordesignerObjectsDiagram>
\ No newline at end of file diff --git a/samples/OAuthAuthorizationServer/Code/DataClasses.designer.cs b/samples/OAuthAuthorizationServer/Code/DataClasses.designer.cs index b6d070d..c8d1b19 100644 --- a/samples/OAuthAuthorizationServer/Code/DataClasses.designer.cs +++ b/samples/OAuthAuthorizationServer/Code/DataClasses.designer.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:4.0.30319.1 +// Runtime Version:4.0.30319.225 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -42,6 +42,9 @@ namespace OAuthAuthorizationServer.Code partial void InsertNonce(Nonce instance); partial void UpdateNonce(Nonce instance); partial void DeleteNonce(Nonce instance); + partial void InsertSymmetricCryptoKey(SymmetricCryptoKey instance); + partial void UpdateSymmetricCryptoKey(SymmetricCryptoKey instance); + partial void DeleteSymmetricCryptoKey(SymmetricCryptoKey instance); #endregion public DataClassesDataContext() : @@ -105,6 +108,14 @@ namespace OAuthAuthorizationServer.Code return this.GetTable<Nonce>(); } } + + public System.Data.Linq.Table<SymmetricCryptoKey> SymmetricCryptoKeys + { + get + { + return this.GetTable<SymmetricCryptoKey>(); + } + } } [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.[User]")] @@ -804,5 +815,139 @@ namespace OAuthAuthorizationServer.Code } } } + + [global::System.Data.Linq.Mapping.TableAttribute(Name="")] + public partial class SymmetricCryptoKey : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); + + private string _Bucket; + + private string _Handle; + + private System.DateTime _ExpiresUtc; + + private byte[] _Secret; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnBucketChanging(string value); + partial void OnBucketChanged(); + partial void OnHandleChanging(string value); + partial void OnHandleChanged(); + partial void OnExpiresUtcChanging(System.DateTime value); + partial void OnExpiresUtcChanged(); + partial void OnSecretChanging(byte[] value); + partial void OnSecretChanged(); + #endregion + + public SymmetricCryptoKey() + { + OnCreated(); + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Bucket", CanBeNull=false, IsPrimaryKey=true, UpdateCheck=UpdateCheck.Never)] + public string Bucket + { + get + { + return this._Bucket; + } + set + { + if ((this._Bucket != value)) + { + this.OnBucketChanging(value); + this.SendPropertyChanging(); + this._Bucket = value; + this.SendPropertyChanged("Bucket"); + this.OnBucketChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Handle", CanBeNull=false, IsPrimaryKey=true, UpdateCheck=UpdateCheck.Never)] + public string Handle + { + get + { + return this._Handle; + } + set + { + if ((this._Handle != value)) + { + this.OnHandleChanging(value); + this.SendPropertyChanging(); + this._Handle = value; + this.SendPropertyChanged("Handle"); + this.OnHandleChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExpiresUtc", UpdateCheck=UpdateCheck.Never)] + public System.DateTime ExpiresUtc + { + get + { + return this._ExpiresUtc; + } + set + { + if ((this._ExpiresUtc != value)) + { + this.OnExpiresUtcChanging(value); + this.SendPropertyChanging(); + this._ExpiresUtc = value; + this.SendPropertyChanged("ExpiresUtc"); + this.OnExpiresUtcChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Secret", CanBeNull=false, UpdateCheck=UpdateCheck.Never)] + public byte[] Secret + { + get + { + return this._Secret; + } + set + { + if ((this._Secret != value)) + { + this.OnSecretChanging(value); + this.SendPropertyChanging(); + this._Secret = value; + this.SendPropertyChanged("Secret"); + this.OnSecretChanged(); + } + } + } + + public event PropertyChangingEventHandler PropertyChanging; + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void SendPropertyChanging() + { + if ((this.PropertyChanging != null)) + { + this.PropertyChanging(this, emptyChangingEventArgs); + } + } + + protected virtual void SendPropertyChanged(String propertyName) + { + if ((this.PropertyChanged != null)) + { + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } } #pragma warning restore 1591 diff --git a/samples/OAuthAuthorizationServer/Code/DatabaseNonceStore.cs b/samples/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs index a0ce19e..0a1d8af 100644 --- a/samples/OAuthAuthorizationServer/Code/DatabaseNonceStore.cs +++ b/samples/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs @@ -1,16 +1,18 @@ namespace OAuthAuthorizationServer.Code { using System; + using System.Collections.Generic; using System.Data.SqlClient; + using System.Linq; using DotNetOpenAuth.Messaging.Bindings; /// <summary> /// A database-persisted nonce store. /// </summary> - public class DatabaseNonceStore : INonceStore { + public class DatabaseKeyNonceStore : INonceStore, ICryptoKeyStore { /// <summary> - /// Initializes a new instance of the <see cref="DatabaseNonceStore"/> class. + /// Initializes a new instance of the <see cref="DatabaseKeyNonceStore"/> class. /// </summary> - public DatabaseNonceStore() { + public DatabaseKeyNonceStore() { } #region INonceStore Members @@ -51,5 +53,44 @@ } #endregion + + #region ICryptoKeyStore Members + + public CryptoKey GetKey(string bucket, string handle) { + // It is critical that this lookup be case-sensitive, which can only be configured at the database. + var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys + where key.Bucket == bucket && key.Handle == handle + select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()); + + return matches.FirstOrDefault(); + } + + public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) { + return from key in MvcApplication.DataContext.SymmetricCryptoKeys + where key.Bucket == bucket + orderby key.ExpiresUtc descending + select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())); + } + + public void StoreKey(string bucket, string handle, CryptoKey key) { + var keyRow = new SymmetricCryptoKey() { + Bucket = bucket, + Handle = handle, + Secret = key.Key, + ExpiresUtc = key.ExpiresUtc, + }; + + MvcApplication.DataContext.SymmetricCryptoKeys.InsertOnSubmit(keyRow); + MvcApplication.DataContext.SubmitChanges(); + } + + public void RemoveKey(string bucket, string handle) { + var match = MvcApplication.DataContext.SymmetricCryptoKeys.FirstOrDefault(k => k.Bucket == bucket && k.Handle == handle); + if (match != null) { + MvcApplication.DataContext.SymmetricCryptoKeys.DeleteOnSubmit(match); + } + } + + #endregion } }
\ No newline at end of file diff --git a/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs b/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs index 7e4dba6..d2583a2 100644 --- a/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs +++ b/samples/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs @@ -13,68 +13,14 @@ internal class OAuth2AuthorizationServer : IAuthorizationServer { private static readonly RSAParameters AsymmetricTokenSigningPrivateKey = CreateRSAKey(); - private static readonly byte[] secret = CreateSecret(); - - private readonly INonceStore nonceStore = new DatabaseNonceStore(); - - /// <summary> - /// Creates a symmetric secret used to sign and encrypt authorization server refresh tokens. - /// </summary> - /// <returns>A cryptographically strong symmetric key.</returns> - private static byte[] CreateSecret() { - // TODO: Replace this sample code with real code. - // For this sample, we just generate random secrets. - RandomNumberGenerator crypto = new RNGCryptoServiceProvider(); - var secret = new byte[16]; - crypto.GetBytes(secret); - return secret; - } - - /// <summary> - /// Creates the RSA key used by all the crypto service provider instances we create. - /// </summary> - /// <returns>RSA data that includes the private key.</returns> - private static RSAParameters CreateRSAKey() { -#if SAMPLESONLY - // Since the sample authorization server and the sample resource server must work together, - // we hard-code a FOR SAMPLE USE ONLY key pair. The matching public key information is hard-coded into the OAuthResourceServer sample. - // In a real app, the RSA parameters would typically come from a certificate that may already exist. It may simply be the HTTPS certificate for the auth server. - return new RSAParameters { - Exponent = new byte[] { 1, 0, 1 }, - Modulus = new byte[] { 210, 95, 53, 12, 203, 114, 150, 23, 23, 88, 4, 200, 47, 219, 73, 54, 146, 253, 126, 121, 105, 91, 118, 217, 182, 167, 140, 6, 67, 112, 97, 183, 66, 112, 245, 103, 136, 222, 205, 28, 196, 45, 6, 223, 192, 76, 56, 180, 90, 120, 144, 19, 31, 193, 37, 129, 186, 214, 36, 53, 204, 53, 108, 133, 112, 17, 133, 244, 3, 12, 230, 29, 243, 51, 79, 253, 10, 111, 185, 23, 74, 230, 99, 94, 78, 49, 209, 39, 95, 213, 248, 212, 22, 4, 222, 145, 77, 190, 136, 230, 134, 70, 228, 241, 194, 216, 163, 234, 52, 1, 64, 181, 139, 128, 90, 255, 214, 60, 168, 233, 254, 110, 31, 102, 58, 67, 201, 33 }, - P = new byte[] { 237, 238, 79, 75, 29, 57, 145, 201, 57, 177, 215, 108, 40, 77, 232, 237, 113, 38, 157, 195, 174, 134, 188, 175, 121, 28, 11, 236, 80, 146, 12, 38, 8, 12, 104, 46, 6, 247, 14, 149, 196, 23, 130, 116, 141, 137, 225, 74, 84, 111, 44, 163, 55, 10, 246, 154, 195, 158, 186, 241, 162, 11, 217, 77 }, - Q = new byte[] { 226, 89, 29, 67, 178, 205, 30, 152, 184, 165, 15, 152, 131, 245, 141, 80, 150, 3, 224, 136, 188, 248, 149, 36, 200, 250, 207, 156, 224, 79, 150, 191, 84, 214, 233, 173, 95, 192, 55, 123, 124, 255, 53, 85, 11, 233, 156, 66, 14, 27, 27, 163, 108, 199, 90, 37, 118, 38, 78, 171, 80, 26, 101, 37 }, - DP = new byte[] { 108, 176, 122, 132, 131, 187, 50, 191, 203, 157, 84, 29, 82, 100, 20, 205, 178, 236, 195, 17, 10, 254, 253, 222, 226, 226, 79, 8, 10, 222, 76, 178, 106, 230, 208, 8, 134, 162, 1, 133, 164, 232, 96, 109, 193, 226, 132, 138, 33, 252, 15, 86, 23, 228, 232, 54, 86, 186, 130, 7, 179, 208, 217, 217 }, - DQ = new byte[] { 175, 63, 252, 46, 140, 99, 208, 138, 194, 123, 218, 101, 101, 214, 91, 65, 199, 196, 220, 182, 66, 73, 221, 128, 11, 180, 85, 198, 202, 206, 20, 147, 179, 102, 106, 170, 247, 245, 229, 127, 81, 58, 111, 218, 151, 76, 154, 213, 114, 2, 127, 21, 187, 133, 102, 64, 151, 7, 245, 229, 34, 50, 45, 153 }, - InverseQ = new byte[] { 137, 156, 11, 248, 118, 201, 135, 145, 134, 121, 14, 162, 149, 14, 98, 84, 108, 160, 27, 91, 230, 116, 216, 181, 200, 49, 34, 254, 119, 153, 179, 52, 231, 234, 36, 148, 71, 161, 182, 171, 35, 182, 46, 164, 179, 100, 226, 71, 119, 23, 0, 16, 240, 4, 30, 57, 76, 109, 89, 131, 56, 219, 71, 206 }, - D = new byte[] { 108, 15, 123, 176, 150, 208, 197, 72, 23, 53, 159, 63, 53, 85, 238, 197, 153, 187, 156, 187, 192, 226, 186, 170, 26, 168, 245, 196, 65, 223, 248, 81, 170, 79, 91, 191, 83, 15, 31, 77, 39, 119, 249, 143, 245, 183, 49, 105, 115, 15, 122, 242, 87, 221, 94, 230, 196, 146, 59, 7, 103, 94, 9, 223, 146, 180, 189, 86, 190, 94, 242, 59, 32, 54, 23, 181, 124, 170, 63, 172, 90, 158, 169, 140, 6, 102, 170, 0, 135, 199, 35, 196, 212, 238, 196, 56, 14, 0, 140, 197, 169, 240, 156, 43, 182, 123, 102, 79, 89, 20, 120, 171, 43, 223, 58, 190, 230, 166, 185, 162, 186, 226, 31, 206, 196, 188, 104, 1 }, - }; -#else - // This is how you could generate your own public/private key pair. - // As we generate a new random key, we need to set the UseMachineKeyStore flag so that this doesn't - // crash on IIS. For more information: - // http://social.msdn.microsoft.com/Forums/en-US/clr/thread/7ea48fd0-8d6b-43ed-b272-1a0249ae490f?prof=required - var cspParameters = new CspParameters(); - cspParameters.Flags = CspProviderFlags.UseArchivableKey | CspProviderFlags.UseMachineKeyStore; - var keyPair = new RSACryptoServiceProvider(cspParameters); - - // After exporting the private/public key information, read the information out and store it somewhere - var privateKey = keyPair.ExportParameters(true); - var publicKey = keyPair.ExportParameters(false); - - // Ultimately the private key information must be what is returned through the AccessTokenSigningPrivateKey property. - return privateKey; -#endif - } - #region Implementation of IAuthorizationServer - public byte[] Secret { - get { return secret; } + public ICryptoKeyStore CryptoKeyStore { + get { return MvcApplication.KeyNonceStore; } } public INonceStore VerificationCodeNonceStore { - get { return this.nonceStore; } + get { return MvcApplication.KeyNonceStore; } } public RSACryptoServiceProvider CreateAccessTokenSigningCryptoServiceProvider() { @@ -107,7 +53,7 @@ // NEVER issue an auto-approval to a client that would end up getting an access token immediately // (without a client secret), as that would allow ANY client to spoof an approved client's identity // and obtain unauthorized access to user data. - if (authorizationRequest.ResponseType == EndUserAuthorizationResponseType.AuthorizationCode) { + if (EndUserAuthorizationRequest.ResponseType == EndUserAuthorizationResponseTypes.AuthorizationCode) { // Never issue auto-approval if the client secret is blank, since that too makes it easy to spoof // a client's identity and obtain unauthorized access. var requestingClient = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == authorizationRequest.ClientIdentifier); @@ -124,14 +70,55 @@ return false; } + /// <summary> + /// Creates the RSA key used by all the crypto service provider instances we create. + /// </summary> + /// <returns>RSA data that includes the private key.</returns> + private static RSAParameters CreateRSAKey() { +#if SAMPLESONLY + // Since the sample authorization server and the sample resource server must work together, + // we hard-code a FOR SAMPLE USE ONLY key pair. The matching public key information is hard-coded into the OAuthResourceServer sample. + // In a real app, the RSA parameters would typically come from a certificate that may already exist. It may simply be the HTTPS certificate for the auth server. + return new RSAParameters { + Exponent = new byte[] { 1, 0, 1 }, + Modulus = new byte[] { 210, 95, 53, 12, 203, 114, 150, 23, 23, 88, 4, 200, 47, 219, 73, 54, 146, 253, 126, 121, 105, 91, 118, 217, 182, 167, 140, 6, 67, 112, 97, 183, 66, 112, 245, 103, 136, 222, 205, 28, 196, 45, 6, 223, 192, 76, 56, 180, 90, 120, 144, 19, 31, 193, 37, 129, 186, 214, 36, 53, 204, 53, 108, 133, 112, 17, 133, 244, 3, 12, 230, 29, 243, 51, 79, 253, 10, 111, 185, 23, 74, 230, 99, 94, 78, 49, 209, 39, 95, 213, 248, 212, 22, 4, 222, 145, 77, 190, 136, 230, 134, 70, 228, 241, 194, 216, 163, 234, 52, 1, 64, 181, 139, 128, 90, 255, 214, 60, 168, 233, 254, 110, 31, 102, 58, 67, 201, 33 }, + P = new byte[] { 237, 238, 79, 75, 29, 57, 145, 201, 57, 177, 215, 108, 40, 77, 232, 237, 113, 38, 157, 195, 174, 134, 188, 175, 121, 28, 11, 236, 80, 146, 12, 38, 8, 12, 104, 46, 6, 247, 14, 149, 196, 23, 130, 116, 141, 137, 225, 74, 84, 111, 44, 163, 55, 10, 246, 154, 195, 158, 186, 241, 162, 11, 217, 77 }, + Q = new byte[] { 226, 89, 29, 67, 178, 205, 30, 152, 184, 165, 15, 152, 131, 245, 141, 80, 150, 3, 224, 136, 188, 248, 149, 36, 200, 250, 207, 156, 224, 79, 150, 191, 84, 214, 233, 173, 95, 192, 55, 123, 124, 255, 53, 85, 11, 233, 156, 66, 14, 27, 27, 163, 108, 199, 90, 37, 118, 38, 78, 171, 80, 26, 101, 37 }, + DP = new byte[] { 108, 176, 122, 132, 131, 187, 50, 191, 203, 157, 84, 29, 82, 100, 20, 205, 178, 236, 195, 17, 10, 254, 253, 222, 226, 226, 79, 8, 10, 222, 76, 178, 106, 230, 208, 8, 134, 162, 1, 133, 164, 232, 96, 109, 193, 226, 132, 138, 33, 252, 15, 86, 23, 228, 232, 54, 86, 186, 130, 7, 179, 208, 217, 217 }, + DQ = new byte[] { 175, 63, 252, 46, 140, 99, 208, 138, 194, 123, 218, 101, 101, 214, 91, 65, 199, 196, 220, 182, 66, 73, 221, 128, 11, 180, 85, 198, 202, 206, 20, 147, 179, 102, 106, 170, 247, 245, 229, 127, 81, 58, 111, 218, 151, 76, 154, 213, 114, 2, 127, 21, 187, 133, 102, 64, 151, 7, 245, 229, 34, 50, 45, 153 }, + InverseQ = new byte[] { 137, 156, 11, 248, 118, 201, 135, 145, 134, 121, 14, 162, 149, 14, 98, 84, 108, 160, 27, 91, 230, 116, 216, 181, 200, 49, 34, 254, 119, 153, 179, 52, 231, 234, 36, 148, 71, 161, 182, 171, 35, 182, 46, 164, 179, 100, 226, 71, 119, 23, 0, 16, 240, 4, 30, 57, 76, 109, 89, 131, 56, 219, 71, 206 }, + D = new byte[] { 108, 15, 123, 176, 150, 208, 197, 72, 23, 53, 159, 63, 53, 85, 238, 197, 153, 187, 156, 187, 192, 226, 186, 170, 26, 168, 245, 196, 65, 223, 248, 81, 170, 79, 91, 191, 83, 15, 31, 77, 39, 119, 249, 143, 245, 183, 49, 105, 115, 15, 122, 242, 87, 221, 94, 230, 196, 146, 59, 7, 103, 94, 9, 223, 146, 180, 189, 86, 190, 94, 242, 59, 32, 54, 23, 181, 124, 170, 63, 172, 90, 158, 169, 140, 6, 102, 170, 0, 135, 199, 35, 196, 212, 238, 196, 56, 14, 0, 140, 197, 169, 240, 156, 43, 182, 123, 102, 79, 89, 20, 120, 171, 43, 223, 58, 190, 230, 166, 185, 162, 186, 226, 31, 206, 196, 188, 104, 1 }, + }; +#else + // This is how you could generate your own public/private key pair. + // As we generate a new random key, we need to set the UseMachineKeyStore flag so that this doesn't + // crash on IIS. For more information: + // http://social.msdn.microsoft.com/Forums/en-US/clr/thread/7ea48fd0-8d6b-43ed-b272-1a0249ae490f?prof=required + var cspParameters = new CspParameters(); + cspParameters.Flags = CspProviderFlags.UseArchivableKey | CspProviderFlags.UseMachineKeyStore; + var keyPair = new RSACryptoServiceProvider(cspParameters); + + // After exporting the private/public key information, read the information out and store it somewhere + var privateKey = keyPair.ExportParameters(true); + var publicKey = keyPair.ExportParameters(false); + + // Ultimately the private key information must be what is returned through the AccessTokenSigningPrivateKey property. + return privateKey; +#endif + } + private bool IsAuthorizationValid(HashSet<string> requestedScopes, string clientIdentifier, DateTime issuedUtc, string username) { + // If db precision exceeds token time precision (which is common), the following query would + // often disregard a token that is minted immediately after the authorization record is stored in the db. + // To compensate for this, we'll increase the timestamp on the token's issue date by 1 second. + issuedUtc += TimeSpan.FromSeconds(1); var grantedScopeStrings = from auth in MvcApplication.DataContext.ClientAuthorizations - where - auth.Client.ClientIdentifier == clientIdentifier && - auth.CreatedOnUtc <= issuedUtc && - (!auth.ExpirationDateUtc.HasValue || auth.ExpirationDateUtc.Value >= DateTime.UtcNow) && - auth.User.OpenIDClaimedIdentifier == username - select auth.Scope; + where + auth.Client.ClientIdentifier == clientIdentifier && + auth.CreatedOnUtc <= issuedUtc && + (!auth.ExpirationDateUtc.HasValue || auth.ExpirationDateUtc.Value >= DateTime.UtcNow) && + auth.User.OpenIDClaimedIdentifier == username + select auth.Scope; if (!grantedScopeStrings.Any()) { // No granted authorizations prior to the issuance of this token, so it must have been revoked. diff --git a/samples/OAuthAuthorizationServer/Code/Utilities.cs b/samples/OAuthAuthorizationServer/Code/Utilities.cs new file mode 100644 index 0000000..c9109bd --- /dev/null +++ b/samples/OAuthAuthorizationServer/Code/Utilities.cs @@ -0,0 +1,21 @@ +namespace OAuthAuthorizationServer.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + + internal static class Utilities { + /// <summary> + /// Ensures that local times are converted to UTC times. Unspecified kinds are recast to UTC with no conversion. + /// </summary> + /// <param name="value">The date-time to convert.</param> + /// <returns>The date-time in UTC time.</returns> + internal static DateTime AsUtc(this DateTime value) { + if (value.Kind == DateTimeKind.Unspecified) { + return new DateTime(value.Ticks, DateTimeKind.Utc); + } + + return value.ToUniversalTime(); + } + } +}
\ No newline at end of file diff --git a/samples/OAuthAuthorizationServer/Controllers/HomeController.cs b/samples/OAuthAuthorizationServer/Controllers/HomeController.cs index 1887576..1311caa 100644 --- a/samples/OAuthAuthorizationServer/Controllers/HomeController.cs +++ b/samples/OAuthAuthorizationServer/Controllers/HomeController.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Web.Mvc; - + using System.Web.Security; using OAuthAuthorizationServer.Code; [HandleError] @@ -39,6 +39,10 @@ }); dc.SubmitChanges(); + + // Force the user to log out because a new database warrants a new row in the users table, which we create + // when the user logs in. + FormsAuthentication.SignOut(); ViewData["Success"] = true; } catch (SqlException ex) { ViewData["Error"] = string.Join("<br>", ex.Errors.OfType<SqlError>().Select(er => er.Message).ToArray()); diff --git a/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs b/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs index 47c1977..fb836a6 100644 --- a/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs +++ b/samples/OAuthAuthorizationServer/Controllers/OAuthController.cs @@ -35,16 +35,6 @@ #endif
/// <summary>
- /// Creates the resource server's encryption service provider with private key.
- /// </summary>
- /// <returns>An RSA crypto service provider.</returns>
- internal static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() {
- var resourceServerEncryptionServiceProvider = new RSACryptoServiceProvider();
- resourceServerEncryptionServiceProvider.ImportParameters(ResourceServerEncryptionPublicKey);
- return resourceServerEncryptionServiceProvider;
- }
-
- /// <summary>
/// The OAuth 2.0 token endpoint.
/// </summary>
/// <returns>The response to the Client.</returns>
@@ -123,6 +113,7 @@ User = MvcApplication.LoggedInUser,
CreatedOnUtc = DateTime.UtcNow,
});
+ MvcApplication.DataContext.SubmitChanges(); // submit now so that this new row can be retrieved later in this same HTTP request
// In this simple sample, the user either agrees to the entire scope requested by the client or none of it.
// But in a real app, you could grant a reduced scope of access to the client by passing a scope parameter to this method.
@@ -133,5 +124,15 @@ return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
}
+
+ /// <summary>
+ /// Creates the resource server's encryption service provider with private key.
+ /// </summary>
+ /// <returns>An RSA crypto service provider.</returns>
+ internal static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider() {
+ var resourceServerEncryptionServiceProvider = new RSACryptoServiceProvider();
+ resourceServerEncryptionServiceProvider.ImportParameters(ResourceServerEncryptionPublicKey);
+ return resourceServerEncryptionServiceProvider;
+ }
}
}
diff --git a/samples/OAuthAuthorizationServer/Global.asax.cs b/samples/OAuthAuthorizationServer/Global.asax.cs index 2c23ec0..d878ea6 100644 --- a/samples/OAuthAuthorizationServer/Global.asax.cs +++ b/samples/OAuthAuthorizationServer/Global.asax.cs @@ -26,7 +26,7 @@ /// </summary>
public static log4net.ILog Logger = log4net.LogManager.GetLogger("DotNetOpenAuth.OAuthAuthorizationServer");
- public static DatabaseNonceStore NonceStore { get; set; }
+ public static DatabaseKeyNonceStore KeyNonceStore { get; set; }
/// <summary>
/// Gets the transaction-protected database connection for the current request.
@@ -81,7 +81,7 @@ RegisterRoutes(RouteTable.Routes);
- NonceStore = new DatabaseNonceStore();
+ KeyNonceStore = new DatabaseKeyNonceStore();
log4net.Config.XmlConfigurator.Configure();
Logger.Info("Sample starting...");
diff --git a/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj b/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj index 5bb1daf..d00cef4 100644 --- a/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj +++ b/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj @@ -70,13 +70,14 @@ </ItemGroup> <ItemGroup> <Compile Include="Code\Client.cs" /> - <Compile Include="Code\DatabaseNonceStore.cs" /> + <Compile Include="Code\DatabaseKeyNonceStore.cs" /> <Compile Include="Code\DataClasses.designer.cs"> <DependentUpon>DataClasses.dbml</DependentUpon> <DesignTime>True</DesignTime> <AutoGen>True</AutoGen> </Compile> <Compile Include="Code\OAuth2AuthorizationServer.cs" /> + <Compile Include="Code\Utilities.cs" /> <Compile Include="Controllers\AccountController.cs" /> <Compile Include="Controllers\HomeController.cs" /> <Compile Include="Controllers\OAuthController.cs" /> diff --git a/samples/OAuthClient/SampleWcf2.aspx.cs b/samples/OAuthClient/SampleWcf2.aspx.cs index 058ba47..78b46bc 100644 --- a/samples/OAuthClient/SampleWcf2.aspx.cs +++ b/samples/OAuthClient/SampleWcf2.aspx.cs @@ -1,137 +1,137 @@ -namespace OAuthClient { - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Net; - using System.ServiceModel; - using System.ServiceModel.Channels; - using System.ServiceModel.Security; - using System.Web; - using System.Web.UI; - using System.Web.UI.WebControls; - using DotNetOpenAuth.OAuth2; - - using SampleResourceServer; - - public partial class SampleWcf2 : System.Web.UI.Page { - /// <summary> - /// The OAuth 2.0 client object to use to obtain authorization and authorize outgoing HTTP requests. - /// </summary> - private static readonly WebServerClient Client; - - /// <summary> - /// The details about the sample OAuth-enabled WCF service that this sample client calls into. - /// </summary> - private static AuthorizationServerDescription authServerDescription = new AuthorizationServerDescription { - TokenEndpoint = new Uri("http://localhost:50172/OAuth/Token"), - AuthorizationEndpoint = new Uri("http://localhost:50172/OAuth/Authorize"), - }; - - /// <summary> - /// Initializes static members of the <see cref="SampleWcf2"/> class. - /// </summary> - static SampleWcf2() { - Client = new WebServerClient(authServerDescription, "sampleconsumer", "samplesecret"); - } - - /// <summary> - /// Gets or sets the authorization details for the logged in user. - /// </summary> - /// <value>The authorization details.</value> - /// <remarks> - /// Because this is a sample, we simply store the authorization information in memory with the user session. - /// A real web app should store at least the access and refresh tokens in this object in a database associated with the user. - /// </remarks> - private static IAuthorizationState Authorization { - get { return (AuthorizationState)HttpContext.Current.Session["Authorization"]; } - set { HttpContext.Current.Session["Authorization"] = value; } - } - - protected void Page_Load(object sender, EventArgs e) { - if (!IsPostBack) { - // Check to see if we're receiving a end user authorization response. - var authorization = Client.ProcessUserAuthorization(); - if (authorization != null) { - // We are receiving an authorization response. Store it and associate it with this user. - Authorization = authorization; - Response.Redirect(Request.Path); // get rid of the /?code= parameter - } - } - - if (Authorization != null) { - // Indicate to the user that we have already obtained authorization on some of these. - foreach (var li in this.scopeList.Items.OfType<ListItem>().Where(li => Authorization.Scope.Contains(li.Value))) { - li.Selected = true; - } - this.authorizationLabel.Text = "Authorization received!"; - if (Authorization.AccessTokenExpirationUtc.HasValue) { +namespace OAuthClient {
+ using System;
+ using System.Collections.Generic;
+ using System.Globalization;
+ using System.Linq;
+ using System.Net;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Security;
+ using System.Web;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+ using DotNetOpenAuth.OAuth2;
+
+ using SampleResourceServer;
+
+ public partial class SampleWcf2 : System.Web.UI.Page {
+ /// <summary>
+ /// The OAuth 2.0 client object to use to obtain authorization and authorize outgoing HTTP requests.
+ /// </summary>
+ private static readonly WebServerClient Client;
+
+ /// <summary>
+ /// The details about the sample OAuth-enabled WCF service that this sample client calls into.
+ /// </summary>
+ private static AuthorizationServerDescription authServerDescription = new AuthorizationServerDescription {
+ TokenEndpoint = new Uri("http://localhost:50172/OAuth/Token"),
+ AuthorizationEndpoint = new Uri("http://localhost:50172/OAuth/Authorize"),
+ };
+
+ /// <summary>
+ /// Initializes static members of the <see cref="SampleWcf2"/> class.
+ /// </summary>
+ static SampleWcf2() {
+ Client = new WebServerClient(authServerDescription, "sampleconsumer", "samplesecret");
+ }
+
+ /// <summary>
+ /// Gets or sets the authorization details for the logged in user.
+ /// </summary>
+ /// <value>The authorization details.</value>
+ /// <remarks>
+ /// Because this is a sample, we simply store the authorization information in memory with the user session.
+ /// A real web app should store at least the access and refresh tokens in this object in a database associated with the user.
+ /// </remarks>
+ private static IAuthorizationState Authorization {
+ get { return (AuthorizationState)HttpContext.Current.Session["Authorization"]; }
+ set { HttpContext.Current.Session["Authorization"] = value; }
+ }
+
+ protected void Page_Load(object sender, EventArgs e) {
+ if (!IsPostBack) {
+ // Check to see if we're receiving a end user authorization response.
+ var authorization = Client.ProcessUserAuthorization();
+ if (authorization != null) {
+ // We are receiving an authorization response. Store it and associate it with this user.
+ Authorization = authorization;
+ Response.Redirect(Request.Path); // get rid of the /?code= parameter
+ }
+ }
+
+ if (Authorization != null) {
+ // Indicate to the user that we have already obtained authorization on some of these.
+ foreach (var li in this.scopeList.Items.OfType<ListItem>().Where(li => Authorization.Scope.Contains(li.Value))) {
+ li.Selected = true;
+ }
+ this.authorizationLabel.Text = "Authorization received!";
+ if (Authorization.AccessTokenExpirationUtc.HasValue) {
TimeSpan timeLeft = Authorization.AccessTokenExpirationUtc.Value - DateTime.UtcNow;
- this.authorizationLabel.Text += string.Format(CultureInfo.CurrentCulture, " (access token expires in {0} minutes)", Math.Round(timeLeft.TotalMinutes, 1)); - } - } - - this.getNameButton.Enabled = this.getAgeButton.Enabled = this.getFavoriteSites.Enabled = Authorization != null; - } - - protected void getAuthorizationButton_Click(object sender, EventArgs e) { - string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>() - where item.Selected - select item.Value).ToArray(); - - Client.RequestUserAuthorization(scopes); - } - - protected void getNameButton_Click(object sender, EventArgs e) { - try { - this.nameLabel.Text = CallService(client => client.GetName()); - } catch (SecurityAccessDeniedException) { - this.nameLabel.Text = "Access denied!"; - } - } - - protected void getAgeButton_Click(object sender, EventArgs e) { - try { - int? age = CallService(client => client.GetAge()); - this.ageLabel.Text = age.HasValue ? age.Value.ToString(CultureInfo.CurrentCulture) : "not available"; - } catch (SecurityAccessDeniedException) { - this.ageLabel.Text = "Access denied!"; - } - } - - protected void getFavoriteSites_Click(object sender, EventArgs e) { - try { - string[] favoriteSites = CallService(client => client.GetFavoriteSites()); - this.favoriteSitesLabel.Text = string.Join(", ", favoriteSites); - } catch (SecurityAccessDeniedException) { - this.favoriteSitesLabel.Text = "Access denied!"; - } - } - - private T CallService<T>(Func<DataApiClient, T> predicate) { - if (Authorization == null) { - throw new InvalidOperationException("No access token!"); - } - - var wcfClient = new DataApiClient(); - - // Refresh the access token if it expires and if its lifetime is too short to be of use. - if (Authorization.AccessTokenExpirationUtc.HasValue) { - if (Client.RefreshToken(Authorization, TimeSpan.FromSeconds(30))) { + this.authorizationLabel.Text += string.Format(CultureInfo.CurrentCulture, " (access token expires in {0} minutes)", Math.Round(timeLeft.TotalMinutes, 1));
+ }
+ }
+
+ this.getNameButton.Enabled = this.getAgeButton.Enabled = this.getFavoriteSites.Enabled = Authorization != null;
+ }
+
+ protected void getAuthorizationButton_Click(object sender, EventArgs e) {
+ string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>()
+ where item.Selected
+ select item.Value).ToArray();
+
+ Client.RequestUserAuthorization(scopes);
+ }
+
+ protected void getNameButton_Click(object sender, EventArgs e) {
+ try {
+ this.nameLabel.Text = CallService(client => client.GetName());
+ } catch (SecurityAccessDeniedException) {
+ this.nameLabel.Text = "Access denied!";
+ }
+ }
+
+ protected void getAgeButton_Click(object sender, EventArgs e) {
+ try {
+ int? age = CallService(client => client.GetAge());
+ this.ageLabel.Text = age.HasValue ? age.Value.ToString(CultureInfo.CurrentCulture) : "not available";
+ } catch (SecurityAccessDeniedException) {
+ this.ageLabel.Text = "Access denied!";
+ }
+ }
+
+ protected void getFavoriteSites_Click(object sender, EventArgs e) {
+ try {
+ string[] favoriteSites = CallService(client => client.GetFavoriteSites());
+ this.favoriteSitesLabel.Text = string.Join(", ", favoriteSites);
+ } catch (SecurityAccessDeniedException) {
+ this.favoriteSitesLabel.Text = "Access denied!";
+ }
+ }
+
+ private T CallService<T>(Func<DataApiClient, T> predicate) {
+ if (Authorization == null) {
+ throw new InvalidOperationException("No access token!");
+ }
+
+ var wcfClient = new DataApiClient();
+
+ // Refresh the access token if it expires and if its lifetime is too short to be of use.
+ if (Authorization.AccessTokenExpirationUtc.HasValue) {
+ if (Client.RefreshToken(Authorization, TimeSpan.FromSeconds(30))) {
TimeSpan timeLeft = Authorization.AccessTokenExpirationUtc.Value - DateTime.UtcNow;
- this.authorizationLabel.Text += string.Format(CultureInfo.CurrentCulture, " - just renewed for {0} more minutes)", Math.Round(timeLeft.TotalMinutes, 1)); - } - } - - var httpRequest = (HttpWebRequest)WebRequest.Create(wcfClient.Endpoint.Address.Uri); - Client.AuthorizeRequest(httpRequest, Authorization.AccessToken); - - var httpDetails = new HttpRequestMessageProperty(); - httpDetails.Headers[HttpRequestHeader.Authorization] = httpRequest.Headers[HttpRequestHeader.Authorization]; - using (var scope = new OperationContextScope(wcfClient.InnerChannel)) { - OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpDetails; - return predicate(wcfClient); - } - } - } + this.authorizationLabel.Text += string.Format(CultureInfo.CurrentCulture, " - just renewed for {0} more minutes)", Math.Round(timeLeft.TotalMinutes, 1));
+ }
+ }
+
+ var httpRequest = (HttpWebRequest)WebRequest.Create(wcfClient.Endpoint.Address.Uri);
+ ClientBase.AuthorizeRequest(httpRequest, Authorization.AccessToken);
+
+ var httpDetails = new HttpRequestMessageProperty();
+ httpDetails.Headers[HttpRequestHeader.Authorization] = httpRequest.Headers[HttpRequestHeader.Authorization];
+ using (var scope = new OperationContextScope(wcfClient.InnerChannel)) {
+ OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpDetails;
+ return predicate(wcfClient);
+ }
+ }
+ }
}
\ No newline at end of file diff --git a/samples/OpenIdProviderWebForms/Code/CustomStore.cs b/samples/OpenIdProviderWebForms/Code/CustomStore.cs index 7face0b..b2316a4 100644 --- a/samples/OpenIdProviderWebForms/Code/CustomStore.cs +++ b/samples/OpenIdProviderWebForms/Code/CustomStore.cs @@ -6,10 +6,13 @@ namespace OpenIdProviderWebForms.Code { using System; + using System.Collections.Generic; using System.Data; using System.Globalization; + using DotNetOpenAuth; + using DotNetOpenAuth.Configuration; + using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OpenId; - using DotNetOpenAuth.OpenId.Provider; /// <summary> /// This custom store serializes all elements to demonstrate peristent and/or shared storage. @@ -21,59 +24,9 @@ namespace OpenIdProviderWebForms.Code { /// But we "persist" all associations and nonces into a DataTable to demonstrate /// that using a database is possible. /// </remarks> - public class CustomStore : IProviderApplicationStore { + public class CustomStore : IOpenIdApplicationStore { private static CustomStoreDataSet dataSet = new CustomStoreDataSet(); - #region IAssociationStore<AssociationRelyingPartyType> Members - - public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association assoc) { - var assocRow = dataSet.Association.NewAssociationRow(); - assocRow.DistinguishingFactor = distinguishingFactor.ToString(); - assocRow.Handle = assoc.Handle; - assocRow.Expires = assoc.Expires.ToLocalTime(); - assocRow.PrivateData = assoc.SerializePrivateData(); - dataSet.Association.AddAssociationRow(assocRow); - } - - public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, SecuritySettings securitySettings) { - // TODO: properly consider the securitySettings when picking an association to return. - // properly escape the URL to prevent injection attacks. - string value = distinguishingFactor.ToString(); - string filter = string.Format( - CultureInfo.InvariantCulture, - "{0} = '{1}'", - dataSet.Association.DistinguishingFactorColumn.ColumnName, - value); - string sort = dataSet.Association.ExpiresColumn.ColumnName + " DESC"; - DataView view = new DataView(dataSet.Association, filter, sort, DataViewRowState.CurrentRows); - if (view.Count == 0) { - return null; - } - var row = (CustomStoreDataSet.AssociationRow)view[0].Row; - return Association.Deserialize(row.Handle, row.Expires.ToUniversalTime(), row.PrivateData); - } - - public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) { - var assocRow = dataSet.Association.FindByDistinguishingFactorHandle(distinguishingFactor.ToString(), handle); - return Association.Deserialize(assocRow.Handle, assocRow.Expires, assocRow.PrivateData); - } - - public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) { - var row = dataSet.Association.FindByDistinguishingFactorHandle(distinguishingFactor.ToString(), handle); - if (row != null) { - dataSet.Association.RemoveAssociationRow(row); - return true; - } else { - return false; - } - } - - public void ClearExpiredAssociations() { - this.removeExpiredRows(dataSet.Association, dataSet.Association.ExpiresColumn.ColumnName); - } - - #endregion - #region INonceStore Members /// <summary> @@ -84,7 +37,7 @@ namespace OpenIdProviderWebForms.Code { /// The context SHOULD be treated as case-sensitive. /// The value will never be <c>null</c> but may be the empty string.</param> /// <param name="nonce">A series of random characters.</param> - /// <param name="timestamp">The timestamp that together with the nonce string make it unique. + /// <param name="timestampUtc">The timestamp that together with the nonce string make it unique. /// The timestamp may also be used by the data store to clear out old nonces.</param> /// <returns> /// True if the nonce+timestamp (combination) was not previously in the database. @@ -97,7 +50,7 @@ namespace OpenIdProviderWebForms.Code { /// is retrieved or set using the /// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property. /// </remarks> - public bool StoreNonce(string context, string nonce, DateTime timestamp) { + public bool StoreNonce(string context, string nonce, DateTime timestampUtc) { // IMPORTANT: If actually persisting to a database that can be reached from // different servers/instances of this class at once, it is vitally important // to protect against race condition attacks by one or more of these: @@ -109,30 +62,73 @@ namespace OpenIdProviderWebForms.Code { // at you in the result of a race condition somewhere in your web site UI code // and display some message to have the user try to log in again, and possibly // warn them about a replay attack. - timestamp = timestamp.ToLocalTime(); lock (this) { - if (dataSet.Nonce.FindByIssuedCodeContext(timestamp, nonce, context) != null) { + if (dataSet.Nonce.FindByIssuedUtcCodeContext(timestampUtc, nonce, context) != null) { return false; } - TimeSpan maxMessageAge = DotNetOpenAuth.Configuration.DotNetOpenAuthSection.Configuration.Messaging.MaximumMessageLifetime; - dataSet.Nonce.AddNonceRow(context, nonce, timestamp, timestamp + maxMessageAge); + TimeSpan maxMessageAge = DotNetOpenAuthSection.Configuration.Messaging.MaximumMessageLifetime; + dataSet.Nonce.AddNonceRow(context, nonce, timestampUtc, timestampUtc + maxMessageAge); return true; } } public void ClearExpiredNonces() { - this.removeExpiredRows(dataSet.Nonce, dataSet.Nonce.ExpiresColumn.ColumnName); + this.removeExpiredRows(dataSet.Nonce, dataSet.Nonce.ExpiresUtcColumn.ColumnName); } #endregion - private void removeExpiredRows(DataTable table, string expiredColumnName) { + #region ICryptoKeyStore Members + + public CryptoKey GetKey(string bucket, string handle) { + var assocRow = dataSet.CryptoKey.FindByBucketHandle(bucket, handle); + return new CryptoKey(assocRow.Secret, assocRow.ExpiresUtc); + } + + public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) { + // properly escape the URL to prevent injection attacks. + string value = bucket.Replace("'", "''"); string filter = string.Format( CultureInfo.InvariantCulture, - "{0} < #{1}#", - expiredColumnName, - DateTime.Now); + "{0} = '{1}'", + dataSet.CryptoKey.BucketColumn.ColumnName, + value); + string sort = dataSet.CryptoKey.ExpiresUtcColumn.ColumnName + " DESC"; + DataView view = new DataView(dataSet.CryptoKey, filter, sort, DataViewRowState.CurrentRows); + if (view.Count == 0) { + yield break; + } + + foreach (CustomStoreDataSet.CryptoKeyRow row in view) { + yield return new KeyValuePair<string, CryptoKey>(row.Handle, new CryptoKey(row.Secret, row.ExpiresUtc)); + } + } + + public void StoreKey(string bucket, string handle, CryptoKey key) { + var cryptoKeyRow = dataSet.CryptoKey.NewCryptoKeyRow(); + cryptoKeyRow.Bucket = bucket; + cryptoKeyRow.Handle = handle; + cryptoKeyRow.ExpiresUtc = key.ExpiresUtc; + cryptoKeyRow.Secret = key.Key; + dataSet.CryptoKey.AddCryptoKeyRow(cryptoKeyRow); + } + + public void RemoveKey(string bucket, string handle) { + var row = dataSet.CryptoKey.FindByBucketHandle(bucket, handle); + if (row != null) { + dataSet.CryptoKey.RemoveCryptoKeyRow(row); + } + } + + #endregion + + internal void ClearExpiredSecrets() { + this.removeExpiredRows(dataSet.CryptoKey, dataSet.CryptoKey.ExpiresUtcColumn.ColumnName); + } + + private void removeExpiredRows(DataTable table, string expiredColumnName) { + string filter = string.Format(CultureInfo.InvariantCulture, "{0} < #{1}#", expiredColumnName, DateTime.UtcNow); DataView view = new DataView(table, filter, null, DataViewRowState.CurrentRows); for (int i = view.Count - 1; i >= 0; i--) { view.Delete(i); diff --git a/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.Designer.cs b/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.Designer.cs index b8d98ec..19ac88f 100644 --- a/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.Designer.cs +++ b/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:4.0.30104.0 +// Runtime Version:4.0.30319.225 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -24,7 +24,7 @@ namespace OpenIdProviderWebForms.Code { [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.DataSet")] public partial class CustomStoreDataSet : global::System.Data.DataSet { - private AssociationDataTable tableAssociation; + private CryptoKeyDataTable tableCryptoKey; private NonceDataTable tableNonce; @@ -56,8 +56,8 @@ namespace OpenIdProviderWebForms.Code { if ((this.DetermineSchemaSerializationMode(info, context) == global::System.Data.SchemaSerializationMode.IncludeSchema)) { global::System.Data.DataSet ds = new global::System.Data.DataSet(); ds.ReadXmlSchema(new global::System.Xml.XmlTextReader(new global::System.IO.StringReader(strSchema))); - if ((ds.Tables["Association"] != null)) { - base.Tables.Add(new AssociationDataTable(ds.Tables["Association"])); + if ((ds.Tables["CryptoKey"] != null)) { + base.Tables.Add(new CryptoKeyDataTable(ds.Tables["CryptoKey"])); } if ((ds.Tables["Nonce"] != null)) { base.Tables.Add(new NonceDataTable(ds.Tables["Nonce"])); @@ -84,9 +84,9 @@ namespace OpenIdProviderWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] [global::System.ComponentModel.Browsable(false)] [global::System.ComponentModel.DesignerSerializationVisibility(global::System.ComponentModel.DesignerSerializationVisibility.Content)] - public AssociationDataTable Association { + public CryptoKeyDataTable CryptoKey { get { - return this.tableAssociation; + return this.tableCryptoKey; } } @@ -167,8 +167,8 @@ namespace OpenIdProviderWebForms.Code { this.Reset(); global::System.Data.DataSet ds = new global::System.Data.DataSet(); ds.ReadXml(reader); - if ((ds.Tables["Association"] != null)) { - base.Tables.Add(new AssociationDataTable(ds.Tables["Association"])); + if ((ds.Tables["CryptoKey"] != null)) { + base.Tables.Add(new CryptoKeyDataTable(ds.Tables["CryptoKey"])); } if ((ds.Tables["Nonce"] != null)) { base.Tables.Add(new NonceDataTable(ds.Tables["Nonce"])); @@ -206,10 +206,10 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] internal void InitVars(bool initTable) { - this.tableAssociation = ((AssociationDataTable)(base.Tables["Association"])); + this.tableCryptoKey = ((CryptoKeyDataTable)(base.Tables["CryptoKey"])); if ((initTable == true)) { - if ((this.tableAssociation != null)) { - this.tableAssociation.InitVars(); + if ((this.tableCryptoKey != null)) { + this.tableCryptoKey.InitVars(); } } this.tableNonce = ((NonceDataTable)(base.Tables["Nonce"])); @@ -228,15 +228,15 @@ namespace OpenIdProviderWebForms.Code { this.Namespace = "http://tempuri.org/CustomStoreDataSet.xsd"; this.EnforceConstraints = true; this.SchemaSerializationMode = global::System.Data.SchemaSerializationMode.IncludeSchema; - this.tableAssociation = new AssociationDataTable(); - base.Tables.Add(this.tableAssociation); + this.tableCryptoKey = new CryptoKeyDataTable(); + base.Tables.Add(this.tableCryptoKey); this.tableNonce = new NonceDataTable(); base.Tables.Add(this.tableNonce); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - private bool ShouldSerializeAssociation() { + private bool ShouldSerializeCryptoKey() { return false; } @@ -302,7 +302,7 @@ namespace OpenIdProviderWebForms.Code { } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public delegate void AssociationRowChangeEventHandler(object sender, AssociationRowChangeEvent e); + public delegate void CryptoKeyRowChangeEventHandler(object sender, CryptoKeyRowChangeEvent e); [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public delegate void NonceRowChangeEventHandler(object sender, NonceRowChangeEvent e); @@ -312,20 +312,20 @@ namespace OpenIdProviderWebForms.Code { ///</summary> [global::System.Serializable()] [global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")] - public partial class AssociationDataTable : global::System.Data.TypedTableBase<AssociationRow> { + public partial class CryptoKeyDataTable : global::System.Data.TypedTableBase<CryptoKeyRow> { - private global::System.Data.DataColumn columnDistinguishingFactor; + private global::System.Data.DataColumn columnBucket; private global::System.Data.DataColumn columnHandle; - private global::System.Data.DataColumn columnExpires; + private global::System.Data.DataColumn columnExpiresUtc; - private global::System.Data.DataColumn columnPrivateData; + private global::System.Data.DataColumn columnSecret; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationDataTable() { - this.TableName = "Association"; + public CryptoKeyDataTable() { + this.TableName = "CryptoKey"; this.BeginInit(); this.InitClass(); this.EndInit(); @@ -333,7 +333,7 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - internal AssociationDataTable(global::System.Data.DataTable table) { + internal CryptoKeyDataTable(global::System.Data.DataTable table) { this.TableName = table.TableName; if ((table.CaseSensitive != table.DataSet.CaseSensitive)) { this.CaseSensitive = table.CaseSensitive; @@ -350,16 +350,16 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - protected AssociationDataTable(global::System.Runtime.Serialization.SerializationInfo info, global::System.Runtime.Serialization.StreamingContext context) : + protected CryptoKeyDataTable(global::System.Runtime.Serialization.SerializationInfo info, global::System.Runtime.Serialization.StreamingContext context) : base(info, context) { this.InitVars(); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn DistinguishingFactorColumn { + public global::System.Data.DataColumn BucketColumn { get { - return this.columnDistinguishingFactor; + return this.columnBucket; } } @@ -373,17 +373,17 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn ExpiresColumn { + public global::System.Data.DataColumn ExpiresUtcColumn { get { - return this.columnExpires; + return this.columnExpiresUtc; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn PrivateDataColumn { + public global::System.Data.DataColumn SecretColumn { get { - return this.columnPrivateData; + return this.columnSecret; } } @@ -398,56 +398,56 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow this[int index] { + public CryptoKeyRow this[int index] { get { - return ((AssociationRow)(this.Rows[index])); + return ((CryptoKeyRow)(this.Rows[index])); } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowChanging; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowChanging; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowChanged; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowChanged; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowDeleting; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowDeleting; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowDeleted; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowDeleted; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public void AddAssociationRow(AssociationRow row) { + public void AddCryptoKeyRow(CryptoKeyRow row) { this.Rows.Add(row); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow AddAssociationRow(string DistinguishingFactor, string Handle, System.DateTime Expires, byte[] PrivateData) { - AssociationRow rowAssociationRow = ((AssociationRow)(this.NewRow())); + public CryptoKeyRow AddCryptoKeyRow(string Bucket, string Handle, System.DateTime ExpiresUtc, byte[] Secret) { + CryptoKeyRow rowCryptoKeyRow = ((CryptoKeyRow)(this.NewRow())); object[] columnValuesArray = new object[] { - DistinguishingFactor, + Bucket, Handle, - Expires, - PrivateData}; - rowAssociationRow.ItemArray = columnValuesArray; - this.Rows.Add(rowAssociationRow); - return rowAssociationRow; + ExpiresUtc, + Secret}; + rowCryptoKeyRow.ItemArray = columnValuesArray; + this.Rows.Add(rowCryptoKeyRow); + return rowCryptoKeyRow; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow FindByDistinguishingFactorHandle(string DistinguishingFactor, string Handle) { - return ((AssociationRow)(this.Rows.Find(new object[] { - DistinguishingFactor, + public CryptoKeyRow FindByBucketHandle(string Bucket, string Handle) { + return ((CryptoKeyRow)(this.Rows.Find(new object[] { + Bucket, Handle}))); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public override global::System.Data.DataTable Clone() { - AssociationDataTable cln = ((AssociationDataTable)(base.Clone())); + CryptoKeyDataTable cln = ((CryptoKeyDataTable)(base.Clone())); cln.InitVars(); return cln; } @@ -455,62 +455,65 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Data.DataTable CreateInstance() { - return new AssociationDataTable(); + return new CryptoKeyDataTable(); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] internal void InitVars() { - this.columnDistinguishingFactor = base.Columns["DistinguishingFactor"]; + this.columnBucket = base.Columns["Bucket"]; this.columnHandle = base.Columns["Handle"]; - this.columnExpires = base.Columns["Expires"]; - this.columnPrivateData = base.Columns["PrivateData"]; + this.columnExpiresUtc = base.Columns["ExpiresUtc"]; + this.columnSecret = base.Columns["Secret"]; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] private void InitClass() { - this.columnDistinguishingFactor = new global::System.Data.DataColumn("DistinguishingFactor", typeof(string), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnDistinguishingFactor); + this.columnBucket = new global::System.Data.DataColumn("Bucket", typeof(string), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnBucket); this.columnHandle = new global::System.Data.DataColumn("Handle", typeof(string), null, global::System.Data.MappingType.Element); base.Columns.Add(this.columnHandle); - this.columnExpires = new global::System.Data.DataColumn("Expires", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnExpires); - this.columnPrivateData = new global::System.Data.DataColumn("PrivateData", typeof(byte[]), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnPrivateData); + this.columnExpiresUtc = new global::System.Data.DataColumn("ExpiresUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnExpiresUtc); + this.columnSecret = new global::System.Data.DataColumn("Secret", typeof(byte[]), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnSecret); this.Constraints.Add(new global::System.Data.UniqueConstraint("PrimaryKey", new global::System.Data.DataColumn[] { - this.columnDistinguishingFactor, + this.columnBucket, this.columnHandle}, true)); - this.columnDistinguishingFactor.AllowDBNull = false; + this.columnBucket.AllowDBNull = false; + this.columnBucket.ReadOnly = true; this.columnHandle.AllowDBNull = false; - this.columnExpires.AllowDBNull = false; - this.columnPrivateData.AllowDBNull = false; + this.columnHandle.ReadOnly = true; + this.columnExpiresUtc.AllowDBNull = false; + this.columnExpiresUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; + this.columnSecret.AllowDBNull = false; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow NewAssociationRow() { - return ((AssociationRow)(this.NewRow())); + public CryptoKeyRow NewCryptoKeyRow() { + return ((CryptoKeyRow)(this.NewRow())); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Data.DataRow NewRowFromBuilder(global::System.Data.DataRowBuilder builder) { - return new AssociationRow(builder); + return new CryptoKeyRow(builder); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Type GetRowType() { - return typeof(AssociationRow); + return typeof(CryptoKeyRow); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowChanged(global::System.Data.DataRowChangeEventArgs e) { base.OnRowChanged(e); - if ((this.AssociationRowChanged != null)) { - this.AssociationRowChanged(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowChanged != null)) { + this.CryptoKeyRowChanged(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -518,8 +521,8 @@ namespace OpenIdProviderWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowChanging(global::System.Data.DataRowChangeEventArgs e) { base.OnRowChanging(e); - if ((this.AssociationRowChanging != null)) { - this.AssociationRowChanging(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowChanging != null)) { + this.CryptoKeyRowChanging(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -527,8 +530,8 @@ namespace OpenIdProviderWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowDeleted(global::System.Data.DataRowChangeEventArgs e) { base.OnRowDeleted(e); - if ((this.AssociationRowDeleted != null)) { - this.AssociationRowDeleted(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowDeleted != null)) { + this.CryptoKeyRowDeleted(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -536,14 +539,14 @@ namespace OpenIdProviderWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowDeleting(global::System.Data.DataRowChangeEventArgs e) { base.OnRowDeleting(e); - if ((this.AssociationRowDeleting != null)) { - this.AssociationRowDeleting(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowDeleting != null)) { + this.CryptoKeyRowDeleting(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public void RemoveAssociationRow(AssociationRow row) { + public void RemoveCryptoKeyRow(CryptoKeyRow row) { this.Rows.Remove(row); } @@ -570,7 +573,7 @@ namespace OpenIdProviderWebForms.Code { type.Attributes.Add(attribute1); global::System.Xml.Schema.XmlSchemaAttribute attribute2 = new global::System.Xml.Schema.XmlSchemaAttribute(); attribute2.Name = "tableTypeName"; - attribute2.FixedValue = "AssociationDataTable"; + attribute2.FixedValue = "CryptoKeyDataTable"; type.Attributes.Add(attribute2); type.Particle = sequence; global::System.Xml.Schema.XmlSchema dsSchema = ds.GetSchemaSerializable(); @@ -622,9 +625,9 @@ namespace OpenIdProviderWebForms.Code { private global::System.Data.DataColumn columnCode; - private global::System.Data.DataColumn columnIssued; + private global::System.Data.DataColumn columnIssuedUtc; - private global::System.Data.DataColumn columnExpires; + private global::System.Data.DataColumn columnExpiresUtc; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] @@ -677,17 +680,17 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn IssuedColumn { + public global::System.Data.DataColumn IssuedUtcColumn { get { - return this.columnIssued; + return this.columnIssuedUtc; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn ExpiresColumn { + public global::System.Data.DataColumn ExpiresUtcColumn { get { - return this.columnExpires; + return this.columnExpiresUtc; } } @@ -728,13 +731,13 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public NonceRow AddNonceRow(string Context, string Code, System.DateTime Issued, System.DateTime Expires) { + public NonceRow AddNonceRow(string Context, string Code, System.DateTime IssuedUtc, System.DateTime ExpiresUtc) { NonceRow rowNonceRow = ((NonceRow)(this.NewRow())); object[] columnValuesArray = new object[] { Context, Code, - Issued, - Expires}; + IssuedUtc, + ExpiresUtc}; rowNonceRow.ItemArray = columnValuesArray; this.Rows.Add(rowNonceRow); return rowNonceRow; @@ -742,9 +745,9 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public NonceRow FindByIssuedCodeContext(System.DateTime Issued, string Code, string Context) { + public NonceRow FindByIssuedUtcCodeContext(System.DateTime IssuedUtc, string Code, string Context) { return ((NonceRow)(this.Rows.Find(new object[] { - Issued, + IssuedUtc, Code, Context}))); } @@ -768,8 +771,8 @@ namespace OpenIdProviderWebForms.Code { internal void InitVars() { this.columnContext = base.Columns["Context"]; this.columnCode = base.Columns["Code"]; - this.columnIssued = base.Columns["Issued"]; - this.columnExpires = base.Columns["Expires"]; + this.columnIssuedUtc = base.Columns["IssuedUtc"]; + this.columnExpiresUtc = base.Columns["ExpiresUtc"]; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -779,18 +782,20 @@ namespace OpenIdProviderWebForms.Code { base.Columns.Add(this.columnContext); this.columnCode = new global::System.Data.DataColumn("Code", typeof(string), null, global::System.Data.MappingType.Element); base.Columns.Add(this.columnCode); - this.columnIssued = new global::System.Data.DataColumn("Issued", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnIssued); - this.columnExpires = new global::System.Data.DataColumn("Expires", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnExpires); + this.columnIssuedUtc = new global::System.Data.DataColumn("IssuedUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnIssuedUtc); + this.columnExpiresUtc = new global::System.Data.DataColumn("ExpiresUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnExpiresUtc); this.Constraints.Add(new global::System.Data.UniqueConstraint("Constraint1", new global::System.Data.DataColumn[] { - this.columnIssued, + this.columnIssuedUtc, this.columnCode, this.columnContext}, true)); this.columnContext.AllowDBNull = false; this.columnCode.AllowDBNull = false; - this.columnIssued.AllowDBNull = false; - this.columnExpires.AllowDBNull = false; + this.columnIssuedUtc.AllowDBNull = false; + this.columnIssuedUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; + this.columnExpiresUtc.AllowDBNull = false; + this.columnExpiresUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -920,25 +925,25 @@ namespace OpenIdProviderWebForms.Code { /// <summary> ///Represents strongly named DataRow class. ///</summary> - public partial class AssociationRow : global::System.Data.DataRow { + public partial class CryptoKeyRow : global::System.Data.DataRow { - private AssociationDataTable tableAssociation; + private CryptoKeyDataTable tableCryptoKey; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - internal AssociationRow(global::System.Data.DataRowBuilder rb) : + internal CryptoKeyRow(global::System.Data.DataRowBuilder rb) : base(rb) { - this.tableAssociation = ((AssociationDataTable)(this.Table)); + this.tableCryptoKey = ((CryptoKeyDataTable)(this.Table)); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public string DistinguishingFactor { + public string Bucket { get { - return ((string)(this[this.tableAssociation.DistinguishingFactorColumn])); + return ((string)(this[this.tableCryptoKey.BucketColumn])); } set { - this[this.tableAssociation.DistinguishingFactorColumn] = value; + this[this.tableCryptoKey.BucketColumn] = value; } } @@ -946,32 +951,32 @@ namespace OpenIdProviderWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public string Handle { get { - return ((string)(this[this.tableAssociation.HandleColumn])); + return ((string)(this[this.tableCryptoKey.HandleColumn])); } set { - this[this.tableAssociation.HandleColumn] = value; + this[this.tableCryptoKey.HandleColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Expires { + public System.DateTime ExpiresUtc { get { - return ((global::System.DateTime)(this[this.tableAssociation.ExpiresColumn])); + return ((global::System.DateTime)(this[this.tableCryptoKey.ExpiresUtcColumn])); } set { - this[this.tableAssociation.ExpiresColumn] = value; + this[this.tableCryptoKey.ExpiresUtcColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public byte[] PrivateData { + public byte[] Secret { get { - return ((byte[])(this[this.tableAssociation.PrivateDataColumn])); + return ((byte[])(this[this.tableCryptoKey.SecretColumn])); } set { - this[this.tableAssociation.PrivateDataColumn] = value; + this[this.tableCryptoKey.SecretColumn] = value; } } } @@ -1014,23 +1019,23 @@ namespace OpenIdProviderWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Issued { + public System.DateTime IssuedUtc { get { - return ((global::System.DateTime)(this[this.tableNonce.IssuedColumn])); + return ((global::System.DateTime)(this[this.tableNonce.IssuedUtcColumn])); } set { - this[this.tableNonce.IssuedColumn] = value; + this[this.tableNonce.IssuedUtcColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Expires { + public System.DateTime ExpiresUtc { get { - return ((global::System.DateTime)(this[this.tableNonce.ExpiresColumn])); + return ((global::System.DateTime)(this[this.tableNonce.ExpiresUtcColumn])); } set { - this[this.tableNonce.ExpiresColumn] = value; + this[this.tableNonce.ExpiresUtcColumn] = value; } } } @@ -1039,22 +1044,22 @@ namespace OpenIdProviderWebForms.Code { ///Row event argument class ///</summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public class AssociationRowChangeEvent : global::System.EventArgs { + public class CryptoKeyRowChangeEvent : global::System.EventArgs { - private AssociationRow eventRow; + private CryptoKeyRow eventRow; private global::System.Data.DataRowAction eventAction; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRowChangeEvent(AssociationRow row, global::System.Data.DataRowAction action) { + public CryptoKeyRowChangeEvent(CryptoKeyRow row, global::System.Data.DataRowAction action) { this.eventRow = row; this.eventAction = action; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow Row { + public CryptoKeyRow Row { get { return this.eventRow; } diff --git a/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.xsd b/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.xsd index 04a96eb..cf3b62e 100644 --- a/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.xsd +++ b/samples/OpenIdProviderWebForms/Code/CustomStoreDataSet.xsd @@ -9,39 +9,39 @@ </DataSource> </xs:appinfo> </xs:annotation> - <xs:element name="CustomStoreDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="CustomStoreDataSet" msprop:Generator_DataSetName="CustomStoreDataSet" msprop:EnableTableAdapterManager="true"> + <xs:element name="CustomStoreDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="CustomStoreDataSet" msprop:Generator_UserDSName="CustomStoreDataSet"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element name="Association" msprop:Generator_UserTableName="Association" msprop:Generator_RowDeletedName="AssociationRowDeleted" msprop:Generator_RowChangedName="AssociationRowChanged" msprop:Generator_RowClassName="AssociationRow" msprop:Generator_RowChangingName="AssociationRowChanging" msprop:Generator_RowEvArgName="AssociationRowChangeEvent" msprop:Generator_RowEvHandlerName="AssociationRowChangeEventHandler" msprop:Generator_TableClassName="AssociationDataTable" msprop:Generator_TableVarName="tableAssociation" msprop:Generator_RowDeletingName="AssociationRowDeleting" msprop:Generator_TablePropName="Association"> + <xs:element name="CryptoKey" msprop:Generator_UserTableName="CryptoKey" msprop:Generator_RowEvArgName="CryptoKeyRowChangeEvent" msprop:Generator_TableVarName="tableCryptoKey" msprop:Generator_TablePropName="CryptoKey" msprop:Generator_RowDeletingName="CryptoKeyRowDeleting" msprop:Generator_RowChangingName="CryptoKeyRowChanging" msprop:Generator_RowDeletedName="CryptoKeyRowDeleted" msprop:Generator_RowEvHandlerName="CryptoKeyRowChangeEventHandler" msprop:Generator_RowChangedName="CryptoKeyRowChanged" msprop:Generator_TableClassName="CryptoKeyDataTable" msprop:Generator_RowClassName="CryptoKeyRow"> <xs:complexType> <xs:sequence> - <xs:element name="DistinguishingFactor" msprop:Generator_UserColumnName="DistinguishingFactor" msprop:Generator_ColumnVarNameInTable="columnDistinguishingFactor" msprop:Generator_ColumnPropNameInRow="DistinguishingFactor" msprop:Generator_ColumnPropNameInTable="DistinguishingFactorColumn" type="xs:string" /> - <xs:element name="Handle" msprop:Generator_UserColumnName="Handle" msprop:Generator_ColumnVarNameInTable="columnHandle" msprop:Generator_ColumnPropNameInRow="Handle" msprop:Generator_ColumnPropNameInTable="HandleColumn" type="xs:string" /> - <xs:element name="Expires" msprop:Generator_UserColumnName="Expires" msprop:Generator_ColumnVarNameInTable="columnExpires" msprop:Generator_ColumnPropNameInRow="Expires" msprop:Generator_ColumnPropNameInTable="ExpiresColumn" type="xs:dateTime" /> - <xs:element name="PrivateData" msprop:Generator_UserColumnName="PrivateData" msprop:Generator_ColumnVarNameInTable="columnPrivateData" msprop:Generator_ColumnPropNameInRow="PrivateData" msprop:Generator_ColumnPropNameInTable="PrivateDataColumn" type="xs:base64Binary" /> + <xs:element name="Bucket" msdata:ReadOnly="true" msprop:Generator_ColumnVarNameInTable="columnBucket" msprop:Generator_ColumnPropNameInRow="Bucket" msprop:Generator_ColumnPropNameInTable="BucketColumn" msprop:Generator_UserColumnName="Bucket" type="xs:string" /> + <xs:element name="Handle" msdata:ReadOnly="true" msprop:Generator_ColumnVarNameInTable="columnHandle" msprop:Generator_ColumnPropNameInRow="Handle" msprop:Generator_ColumnPropNameInTable="HandleColumn" msprop:Generator_UserColumnName="Handle" type="xs:string" /> + <xs:element name="ExpiresUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnExpiresUtc" msprop:Generator_ColumnPropNameInRow="ExpiresUtc" msprop:Generator_ColumnPropNameInTable="ExpiresUtcColumn" msprop:Generator_UserColumnName="ExpiresUtc" type="xs:dateTime" /> + <xs:element name="Secret" msprop:Generator_ColumnVarNameInTable="columnSecret" msprop:Generator_ColumnPropNameInRow="Secret" msprop:Generator_ColumnPropNameInTable="SecretColumn" msprop:Generator_UserColumnName="Secret" type="xs:base64Binary" /> </xs:sequence> </xs:complexType> </xs:element> - <xs:element name="Nonce" msprop:Generator_UserTableName="Nonce" msprop:Generator_RowDeletedName="NonceRowDeleted" msprop:Generator_RowChangedName="NonceRowChanged" msprop:Generator_RowClassName="NonceRow" msprop:Generator_RowChangingName="NonceRowChanging" msprop:Generator_RowEvArgName="NonceRowChangeEvent" msprop:Generator_RowEvHandlerName="NonceRowChangeEventHandler" msprop:Generator_TableClassName="NonceDataTable" msprop:Generator_TableVarName="tableNonce" msprop:Generator_RowDeletingName="NonceRowDeleting" msprop:Generator_TablePropName="Nonce"> + <xs:element name="Nonce" msprop:Generator_UserTableName="Nonce" msprop:Generator_RowEvArgName="NonceRowChangeEvent" msprop:Generator_TableVarName="tableNonce" msprop:Generator_TablePropName="Nonce" msprop:Generator_RowDeletingName="NonceRowDeleting" msprop:Generator_RowChangingName="NonceRowChanging" msprop:Generator_RowDeletedName="NonceRowDeleted" msprop:Generator_RowEvHandlerName="NonceRowChangeEventHandler" msprop:Generator_RowChangedName="NonceRowChanged" msprop:Generator_TableClassName="NonceDataTable" msprop:Generator_RowClassName="NonceRow"> <xs:complexType> <xs:sequence> - <xs:element name="Context" msprop:Generator_UserColumnName="Context" msprop:Generator_ColumnVarNameInTable="columnContext" msprop:Generator_ColumnPropNameInRow="Context" msprop:Generator_ColumnPropNameInTable="ContextColumn" type="xs:string" /> - <xs:element name="Code" msprop:Generator_UserColumnName="Code" msprop:Generator_ColumnPropNameInRow="Code" msprop:Generator_ColumnVarNameInTable="columnCode" msprop:Generator_ColumnPropNameInTable="CodeColumn" type="xs:string" /> - <xs:element name="Issued" msprop:Generator_UserColumnName="Issued" msprop:Generator_ColumnPropNameInRow="Issued" msprop:Generator_ColumnVarNameInTable="columnIssued" msprop:Generator_ColumnPropNameInTable="IssuedColumn" type="xs:dateTime" /> - <xs:element name="Expires" msprop:Generator_UserColumnName="Expires" msprop:Generator_ColumnPropNameInRow="Expires" msprop:Generator_ColumnVarNameInTable="columnExpires" msprop:Generator_ColumnPropNameInTable="ExpiresColumn" type="xs:dateTime" /> + <xs:element name="Context" msprop:Generator_ColumnVarNameInTable="columnContext" msprop:Generator_ColumnPropNameInRow="Context" msprop:Generator_ColumnPropNameInTable="ContextColumn" msprop:Generator_UserColumnName="Context" type="xs:string" /> + <xs:element name="Code" msprop:Generator_ColumnVarNameInTable="columnCode" msprop:Generator_ColumnPropNameInRow="Code" msprop:Generator_ColumnPropNameInTable="CodeColumn" msprop:Generator_UserColumnName="Code" type="xs:string" /> + <xs:element name="IssuedUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnIssuedUtc" msprop:Generator_ColumnPropNameInRow="IssuedUtc" msprop:Generator_ColumnPropNameInTable="IssuedUtcColumn" msprop:Generator_UserColumnName="IssuedUtc" type="xs:dateTime" /> + <xs:element name="ExpiresUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnExpiresUtc" msprop:Generator_ColumnPropNameInRow="ExpiresUtc" msprop:Generator_ColumnPropNameInTable="ExpiresUtcColumn" msprop:Generator_UserColumnName="ExpiresUtc" type="xs:dateTime" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="PrimaryKey" msdata:PrimaryKey="true"> - <xs:selector xpath=".//mstns:Association" /> - <xs:field xpath="mstns:DistinguishingFactor" /> + <xs:selector xpath=".//mstns:CryptoKey" /> + <xs:field xpath="mstns:Bucket" /> <xs:field xpath="mstns:Handle" /> </xs:unique> <xs:unique name="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//mstns:Nonce" /> - <xs:field xpath="mstns:Issued" /> + <xs:field xpath="mstns:IssuedUtc" /> <xs:field xpath="mstns:Code" /> <xs:field xpath="mstns:Context" /> </xs:unique> diff --git a/samples/OpenIdRelyingPartyWebForms/Code/CustomStore.cs b/samples/OpenIdRelyingPartyWebForms/Code/CustomStore.cs index c4a3982..3ab6292 100644 --- a/samples/OpenIdRelyingPartyWebForms/Code/CustomStore.cs +++ b/samples/OpenIdRelyingPartyWebForms/Code/CustomStore.cs @@ -1,10 +1,19 @@ -namespace OpenIdRelyingPartyWebForms.Code { +//----------------------------------------------------------------------- +// <copyright file="CustomStore.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OpenIdRelyingPartyWebForms.Code { using System; + using System.Collections.Generic; using System.Data; using System.Globalization; - using System.Security.Cryptography; + using System.Linq; + using DotNetOpenAuth; + using DotNetOpenAuth.Configuration; + using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OpenId; - using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// This custom store serializes all elements to demonstrate peristent and/or shared storage. @@ -16,7 +25,7 @@ /// But we "persist" all associations and nonces into a DataTable to demonstrate /// that using a database is possible. /// </remarks> - public class CustomStore : IRelyingPartyApplicationStore { + public class CustomStore : IOpenIdApplicationStore { private static CustomStoreDataSet dataSet = new CustomStoreDataSet(); #region INonceStore Members @@ -29,7 +38,7 @@ /// The context SHOULD be treated as case-sensitive. /// The value will never be <c>null</c> but may be the empty string.</param> /// <param name="nonce">A series of random characters.</param> - /// <param name="timestamp">The timestamp that together with the nonce string make it unique. + /// <param name="timestampUtc">The timestamp that together with the nonce string make it unique. /// The timestamp may also be used by the data store to clear out old nonces.</param> /// <returns> /// True if the nonce+timestamp (combination) was not previously in the database. @@ -42,7 +51,7 @@ /// is retrieved or set using the /// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property. /// </remarks> - public bool StoreNonce(string context, string nonce, DateTime timestamp) { + public bool StoreNonce(string context, string nonce, DateTime timestampUtc) { // IMPORTANT: If actually persisting to a database that can be reached from // different servers/instances of this class at once, it is vitally important // to protect against race condition attacks by one or more of these: @@ -54,76 +63,73 @@ // at you in the result of a race condition somewhere in your web site UI code // and display some message to have the user try to log in again, and possibly // warn them about a replay attack. - timestamp = timestamp.ToLocalTime(); lock (this) { - if (dataSet.Nonce.FindByIssuedCodeContext(timestamp, nonce, context) != null) { + if (dataSet.Nonce.FindByIssuedUtcCodeContext(timestampUtc, nonce, context) != null) { return false; } - TimeSpan maxMessageAge = DotNetOpenAuth.Configuration.DotNetOpenAuthSection.Configuration.Messaging.MaximumMessageLifetime; - dataSet.Nonce.AddNonceRow(context, nonce, timestamp, timestamp + maxMessageAge); + TimeSpan maxMessageAge = DotNetOpenAuthSection.Configuration.Messaging.MaximumMessageLifetime; + dataSet.Nonce.AddNonceRow(context, nonce, timestampUtc, timestampUtc + maxMessageAge); return true; } } public void ClearExpiredNonces() { - this.removeExpiredRows(dataSet.Nonce, dataSet.Nonce.ExpiresColumn.ColumnName); + this.removeExpiredRows(dataSet.Nonce, dataSet.Nonce.ExpiresUtcColumn.ColumnName); } #endregion - #region IAssociationStore<Uri> Members + #region ICryptoKeyStore Members - public void StoreAssociation(Uri distinguishingFactor, Association assoc) { - var assocRow = dataSet.Association.NewAssociationRow(); - assocRow.DistinguishingFactor = distinguishingFactor.AbsoluteUri; - assocRow.Handle = assoc.Handle; - assocRow.Expires = assoc.Expires.ToLocalTime(); - assocRow.PrivateData = assoc.SerializePrivateData(); - dataSet.Association.AddAssociationRow(assocRow); + public CryptoKey GetKey(string bucket, string handle) { + var assocRow = dataSet.CryptoKey.FindByBucketHandle(bucket, handle); + return new CryptoKey(assocRow.Secret, assocRow.ExpiresUtc); } - public Association GetAssociation(Uri distinguishingFactor, SecuritySettings securitySettings) { - // TODO: properly consider the securitySettings when picking an association to return. + public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) { // properly escape the URL to prevent injection attacks. - string value = distinguishingFactor.AbsoluteUri.Replace("'", "''"); + string value = bucket.Replace("'", "''"); string filter = string.Format( CultureInfo.InvariantCulture, "{0} = '{1}'", - dataSet.Association.DistinguishingFactorColumn.ColumnName, + dataSet.CryptoKey.BucketColumn.ColumnName, value); - string sort = dataSet.Association.ExpiresColumn.ColumnName + " DESC"; - DataView view = new DataView(dataSet.Association, filter, sort, DataViewRowState.CurrentRows); + string sort = dataSet.CryptoKey.ExpiresUtcColumn.ColumnName + " DESC"; + DataView view = new DataView(dataSet.CryptoKey, filter, sort, DataViewRowState.CurrentRows); if (view.Count == 0) { - return null; + yield break; + } + + foreach (CustomStoreDataSet.CryptoKeyRow row in view.Cast<DataRowView>().Select(rv => rv.Row)) { + yield return new KeyValuePair<string, CryptoKey>(row.Handle, new CryptoKey(row.Secret, row.ExpiresUtc)); } - var row = (CustomStoreDataSet.AssociationRow)view[0].Row; - return Association.Deserialize(row.Handle, row.Expires.ToUniversalTime(), row.PrivateData); } - public Association GetAssociation(Uri distinguishingFactor, string handle) { - var assocRow = dataSet.Association.FindByDistinguishingFactorHandle(distinguishingFactor.AbsoluteUri, handle); - return Association.Deserialize(assocRow.Handle, assocRow.Expires, assocRow.PrivateData); + public void StoreKey(string bucket, string handle, CryptoKey key) { + var cryptoKeyRow = dataSet.CryptoKey.NewCryptoKeyRow(); + cryptoKeyRow.Bucket = bucket; + cryptoKeyRow.Handle = handle; + cryptoKeyRow.ExpiresUtc = key.ExpiresUtc; + cryptoKeyRow.Secret = key.Key; + dataSet.CryptoKey.AddCryptoKeyRow(cryptoKeyRow); } - public bool RemoveAssociation(Uri distinguishingFactor, string handle) { - var row = dataSet.Association.FindByDistinguishingFactorHandle(distinguishingFactor.AbsoluteUri, handle); + public void RemoveKey(string bucket, string handle) { + var row = dataSet.CryptoKey.FindByBucketHandle(bucket, handle); if (row != null) { - dataSet.Association.RemoveAssociationRow(row); - return true; - } else { - return false; + dataSet.CryptoKey.RemoveCryptoKeyRow(row); } } - public void ClearExpiredAssociations() { - this.removeExpiredRows(dataSet.Association, dataSet.Association.ExpiresColumn.ColumnName); - } - #endregion + internal void ClearExpiredSecrets() { + this.removeExpiredRows(dataSet.CryptoKey, dataSet.CryptoKey.ExpiresUtcColumn.ColumnName); + } + private void removeExpiredRows(DataTable table, string expiredColumnName) { - string filter = string.Format(CultureInfo.InvariantCulture, "{0} < #{1}#", expiredColumnName, DateTime.Now); + string filter = string.Format(CultureInfo.InvariantCulture, "{0} < #{1}#", expiredColumnName, DateTime.UtcNow); DataView view = new DataView(table, filter, null, DataViewRowState.CurrentRows); for (int i = view.Count - 1; i >= 0; i--) { view.Delete(i); diff --git a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xsd b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xsd index fa161fd..f3270f6 100644 --- a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xsd +++ b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xsd @@ -9,39 +9,39 @@ </DataSource> </xs:appinfo> </xs:annotation> - <xs:element name="CustomStoreDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="CustomStoreDataSet" msprop:Generator_DataSetName="CustomStoreDataSet" msprop:EnableTableAdapterManager="true"> + <xs:element name="CustomStoreDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="CustomStoreDataSet" msprop:Generator_UserDSName="CustomStoreDataSet"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element name="Association" msprop:Generator_UserTableName="Association" msprop:Generator_RowDeletedName="AssociationRowDeleted" msprop:Generator_RowChangedName="AssociationRowChanged" msprop:Generator_RowClassName="AssociationRow" msprop:Generator_RowChangingName="AssociationRowChanging" msprop:Generator_RowEvArgName="AssociationRowChangeEvent" msprop:Generator_RowEvHandlerName="AssociationRowChangeEventHandler" msprop:Generator_TableClassName="AssociationDataTable" msprop:Generator_TableVarName="tableAssociation" msprop:Generator_RowDeletingName="AssociationRowDeleting" msprop:Generator_TablePropName="Association"> + <xs:element name="CryptoKey" msprop:Generator_UserTableName="CryptoKey" msprop:Generator_RowEvArgName="CryptoKeyRowChangeEvent" msprop:Generator_TableVarName="tableCryptoKey" msprop:Generator_TablePropName="CryptoKey" msprop:Generator_RowDeletingName="CryptoKeyRowDeleting" msprop:Generator_RowChangingName="CryptoKeyRowChanging" msprop:Generator_RowDeletedName="CryptoKeyRowDeleted" msprop:Generator_TableClassName="CryptoKeyDataTable" msprop:Generator_RowChangedName="CryptoKeyRowChanged" msprop:Generator_RowEvHandlerName="CryptoKeyRowChangeEventHandler" msprop:Generator_RowClassName="CryptoKeyRow"> <xs:complexType> <xs:sequence> - <xs:element name="DistinguishingFactor" msprop:Generator_UserColumnName="DistinguishingFactor" msprop:Generator_ColumnPropNameInRow="DistinguishingFactor" msprop:Generator_ColumnVarNameInTable="columnDistinguishingFactor" msprop:Generator_ColumnPropNameInTable="DistinguishingFactorColumn" type="xs:string" /> - <xs:element name="Handle" msprop:Generator_UserColumnName="Handle" msprop:Generator_ColumnPropNameInRow="Handle" msprop:Generator_ColumnVarNameInTable="columnHandle" msprop:Generator_ColumnPropNameInTable="HandleColumn" type="xs:string" /> - <xs:element name="Expires" msprop:Generator_UserColumnName="Expires" msprop:Generator_ColumnPropNameInRow="Expires" msprop:Generator_ColumnVarNameInTable="columnExpires" msprop:Generator_ColumnPropNameInTable="ExpiresColumn" type="xs:dateTime" /> - <xs:element name="PrivateData" msprop:Generator_UserColumnName="PrivateData" msprop:Generator_ColumnPropNameInRow="PrivateData" msprop:Generator_ColumnVarNameInTable="columnPrivateData" msprop:Generator_ColumnPropNameInTable="PrivateDataColumn" type="xs:base64Binary" /> + <xs:element name="Bucket" msprop:Generator_ColumnVarNameInTable="columnBucket" msprop:Generator_ColumnPropNameInRow="Bucket" msprop:Generator_ColumnPropNameInTable="BucketColumn" msprop:Generator_UserColumnName="Bucket" type="xs:string" /> + <xs:element name="Handle" msprop:Generator_ColumnVarNameInTable="columnHandle" msprop:Generator_ColumnPropNameInRow="Handle" msprop:Generator_ColumnPropNameInTable="HandleColumn" msprop:Generator_UserColumnName="Handle" type="xs:string" /> + <xs:element name="ExpiresUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnExpiresUtc" msprop:Generator_ColumnPropNameInRow="ExpiresUtc" msprop:Generator_ColumnPropNameInTable="ExpiresUtcColumn" msprop:Generator_UserColumnName="ExpiresUtc" type="xs:dateTime" /> + <xs:element name="Secret" msprop:Generator_ColumnVarNameInTable="columnSecret" msprop:Generator_ColumnPropNameInRow="Secret" msprop:Generator_ColumnPropNameInTable="SecretColumn" msprop:Generator_UserColumnName="Secret" type="xs:base64Binary" /> </xs:sequence> </xs:complexType> </xs:element> - <xs:element name="Nonce" msprop:Generator_UserTableName="Nonce" msprop:Generator_RowDeletedName="NonceRowDeleted" msprop:Generator_RowChangedName="NonceRowChanged" msprop:Generator_RowClassName="NonceRow" msprop:Generator_RowChangingName="NonceRowChanging" msprop:Generator_RowEvArgName="NonceRowChangeEvent" msprop:Generator_RowEvHandlerName="NonceRowChangeEventHandler" msprop:Generator_TableClassName="NonceDataTable" msprop:Generator_TableVarName="tableNonce" msprop:Generator_RowDeletingName="NonceRowDeleting" msprop:Generator_TablePropName="Nonce"> + <xs:element name="Nonce" msprop:Generator_UserTableName="Nonce" msprop:Generator_RowEvArgName="NonceRowChangeEvent" msprop:Generator_TableVarName="tableNonce" msprop:Generator_TablePropName="Nonce" msprop:Generator_RowDeletingName="NonceRowDeleting" msprop:Generator_RowChangingName="NonceRowChanging" msprop:Generator_RowDeletedName="NonceRowDeleted" msprop:Generator_TableClassName="NonceDataTable" msprop:Generator_RowChangedName="NonceRowChanged" msprop:Generator_RowEvHandlerName="NonceRowChangeEventHandler" msprop:Generator_RowClassName="NonceRow"> <xs:complexType> <xs:sequence> - <xs:element name="Context" msprop:Generator_UserColumnName="Context" msprop:Generator_ColumnVarNameInTable="columnContext" msprop:Generator_ColumnPropNameInRow="Context" msprop:Generator_ColumnPropNameInTable="ContextColumn" type="xs:string" /> - <xs:element name="Code" msprop:Generator_UserColumnName="Code" msprop:Generator_ColumnVarNameInTable="columnCode" msprop:Generator_ColumnPropNameInRow="Code" msprop:Generator_ColumnPropNameInTable="CodeColumn" type="xs:string" /> - <xs:element name="Issued" msprop:Generator_UserColumnName="Issued" msprop:Generator_ColumnVarNameInTable="columnIssued" msprop:Generator_ColumnPropNameInRow="Issued" msprop:Generator_ColumnPropNameInTable="IssuedColumn" type="xs:dateTime" /> - <xs:element name="Expires" msprop:Generator_UserColumnName="Expires" msprop:Generator_ColumnPropNameInRow="Expires" msprop:Generator_ColumnVarNameInTable="columnExpires" msprop:Generator_ColumnPropNameInTable="ExpiresColumn" type="xs:dateTime" /> + <xs:element name="Context" msprop:Generator_ColumnVarNameInTable="columnContext" msprop:Generator_ColumnPropNameInRow="Context" msprop:Generator_ColumnPropNameInTable="ContextColumn" msprop:Generator_UserColumnName="Context" type="xs:string" /> + <xs:element name="Code" msprop:Generator_ColumnVarNameInTable="columnCode" msprop:Generator_ColumnPropNameInRow="Code" msprop:Generator_ColumnPropNameInTable="CodeColumn" msprop:Generator_UserColumnName="Code" type="xs:string" /> + <xs:element name="IssuedUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnIssuedUtc" msprop:Generator_ColumnPropNameInRow="IssuedUtc" msprop:Generator_ColumnPropNameInTable="IssuedUtcColumn" msprop:Generator_UserColumnName="IssuedUtc" type="xs:dateTime" /> + <xs:element name="ExpiresUtc" msdata:DateTimeMode="Utc" msprop:Generator_ColumnVarNameInTable="columnExpiresUtc" msprop:Generator_ColumnPropNameInRow="ExpiresUtc" msprop:Generator_ColumnPropNameInTable="ExpiresUtcColumn" msprop:Generator_UserColumnName="ExpiresUtc" type="xs:dateTime" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="PrimaryKey" msdata:PrimaryKey="true"> - <xs:selector xpath=".//mstns:Association" /> - <xs:field xpath="mstns:DistinguishingFactor" /> + <xs:selector xpath=".//mstns:CryptoKey" /> + <xs:field xpath="mstns:Bucket" /> <xs:field xpath="mstns:Handle" /> </xs:unique> <xs:unique name="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//mstns:Nonce" /> - <xs:field xpath="mstns:Issued" /> + <xs:field xpath="mstns:IssuedUtc" /> <xs:field xpath="mstns:Code" /> <xs:field xpath="mstns:Context" /> </xs:unique> diff --git a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xss b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xss index ab8f226..631148e 100644 --- a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xss +++ b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet.xss @@ -4,9 +4,9 @@ Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. </autogenerated>--> -<DiagramLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ex:showrelationlabel="False" ViewPortX="0" ViewPortY="0" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout"> +<DiagramLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ex:showrelationlabel="False" ViewPortX="-10" ViewPortY="-10" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout"> <Shapes> - <Shape ID="DesignTable:Association" ZOrder="2" X="349" Y="83" Height="105" Width="154" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="101" /> + <Shape ID="DesignTable:CryptoKey" ZOrder="2" X="349" Y="83" Height="105" Width="154" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="101" /> <Shape ID="DesignTable:Nonce" ZOrder="1" X="604" Y="86" Height="125" Width="150" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="121" /> </Shapes> <Connectors /> diff --git a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet1.Designer.cs b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet1.Designer.cs index 9922a4d..fa28b9c 100644 --- a/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet1.Designer.cs +++ b/samples/OpenIdRelyingPartyWebForms/Code/CustomStoreDataSet1.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:4.0.30104.0 +// Runtime Version:4.0.30319.225 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -24,7 +24,7 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.DataSet")] public partial class CustomStoreDataSet : global::System.Data.DataSet { - private AssociationDataTable tableAssociation; + private CryptoKeyDataTable tableCryptoKey; private NonceDataTable tableNonce; @@ -56,8 +56,8 @@ namespace OpenIdRelyingPartyWebForms.Code { if ((this.DetermineSchemaSerializationMode(info, context) == global::System.Data.SchemaSerializationMode.IncludeSchema)) { global::System.Data.DataSet ds = new global::System.Data.DataSet(); ds.ReadXmlSchema(new global::System.Xml.XmlTextReader(new global::System.IO.StringReader(strSchema))); - if ((ds.Tables["Association"] != null)) { - base.Tables.Add(new AssociationDataTable(ds.Tables["Association"])); + if ((ds.Tables["CryptoKey"] != null)) { + base.Tables.Add(new CryptoKeyDataTable(ds.Tables["CryptoKey"])); } if ((ds.Tables["Nonce"] != null)) { base.Tables.Add(new NonceDataTable(ds.Tables["Nonce"])); @@ -84,9 +84,9 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] [global::System.ComponentModel.Browsable(false)] [global::System.ComponentModel.DesignerSerializationVisibility(global::System.ComponentModel.DesignerSerializationVisibility.Content)] - public AssociationDataTable Association { + public CryptoKeyDataTable CryptoKey { get { - return this.tableAssociation; + return this.tableCryptoKey; } } @@ -167,8 +167,8 @@ namespace OpenIdRelyingPartyWebForms.Code { this.Reset(); global::System.Data.DataSet ds = new global::System.Data.DataSet(); ds.ReadXml(reader); - if ((ds.Tables["Association"] != null)) { - base.Tables.Add(new AssociationDataTable(ds.Tables["Association"])); + if ((ds.Tables["CryptoKey"] != null)) { + base.Tables.Add(new CryptoKeyDataTable(ds.Tables["CryptoKey"])); } if ((ds.Tables["Nonce"] != null)) { base.Tables.Add(new NonceDataTable(ds.Tables["Nonce"])); @@ -206,10 +206,10 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] internal void InitVars(bool initTable) { - this.tableAssociation = ((AssociationDataTable)(base.Tables["Association"])); + this.tableCryptoKey = ((CryptoKeyDataTable)(base.Tables["CryptoKey"])); if ((initTable == true)) { - if ((this.tableAssociation != null)) { - this.tableAssociation.InitVars(); + if ((this.tableCryptoKey != null)) { + this.tableCryptoKey.InitVars(); } } this.tableNonce = ((NonceDataTable)(base.Tables["Nonce"])); @@ -228,15 +228,15 @@ namespace OpenIdRelyingPartyWebForms.Code { this.Namespace = "http://tempuri.org/CustomStoreDataSet.xsd"; this.EnforceConstraints = true; this.SchemaSerializationMode = global::System.Data.SchemaSerializationMode.IncludeSchema; - this.tableAssociation = new AssociationDataTable(); - base.Tables.Add(this.tableAssociation); + this.tableCryptoKey = new CryptoKeyDataTable(); + base.Tables.Add(this.tableCryptoKey); this.tableNonce = new NonceDataTable(); base.Tables.Add(this.tableNonce); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - private bool ShouldSerializeAssociation() { + private bool ShouldSerializeCryptoKey() { return false; } @@ -302,7 +302,7 @@ namespace OpenIdRelyingPartyWebForms.Code { } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public delegate void AssociationRowChangeEventHandler(object sender, AssociationRowChangeEvent e); + public delegate void CryptoKeyRowChangeEventHandler(object sender, CryptoKeyRowChangeEvent e); [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public delegate void NonceRowChangeEventHandler(object sender, NonceRowChangeEvent e); @@ -312,20 +312,20 @@ namespace OpenIdRelyingPartyWebForms.Code { ///</summary> [global::System.Serializable()] [global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")] - public partial class AssociationDataTable : global::System.Data.TypedTableBase<AssociationRow> { + public partial class CryptoKeyDataTable : global::System.Data.TypedTableBase<CryptoKeyRow> { - private global::System.Data.DataColumn columnDistinguishingFactor; + private global::System.Data.DataColumn columnBucket; private global::System.Data.DataColumn columnHandle; - private global::System.Data.DataColumn columnExpires; + private global::System.Data.DataColumn columnExpiresUtc; - private global::System.Data.DataColumn columnPrivateData; + private global::System.Data.DataColumn columnSecret; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationDataTable() { - this.TableName = "Association"; + public CryptoKeyDataTable() { + this.TableName = "CryptoKey"; this.BeginInit(); this.InitClass(); this.EndInit(); @@ -333,7 +333,7 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - internal AssociationDataTable(global::System.Data.DataTable table) { + internal CryptoKeyDataTable(global::System.Data.DataTable table) { this.TableName = table.TableName; if ((table.CaseSensitive != table.DataSet.CaseSensitive)) { this.CaseSensitive = table.CaseSensitive; @@ -350,16 +350,16 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - protected AssociationDataTable(global::System.Runtime.Serialization.SerializationInfo info, global::System.Runtime.Serialization.StreamingContext context) : + protected CryptoKeyDataTable(global::System.Runtime.Serialization.SerializationInfo info, global::System.Runtime.Serialization.StreamingContext context) : base(info, context) { this.InitVars(); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn DistinguishingFactorColumn { + public global::System.Data.DataColumn BucketColumn { get { - return this.columnDistinguishingFactor; + return this.columnBucket; } } @@ -373,17 +373,17 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn ExpiresColumn { + public global::System.Data.DataColumn ExpiresUtcColumn { get { - return this.columnExpires; + return this.columnExpiresUtc; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn PrivateDataColumn { + public global::System.Data.DataColumn SecretColumn { get { - return this.columnPrivateData; + return this.columnSecret; } } @@ -398,56 +398,56 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow this[int index] { + public CryptoKeyRow this[int index] { get { - return ((AssociationRow)(this.Rows[index])); + return ((CryptoKeyRow)(this.Rows[index])); } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowChanging; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowChanging; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowChanged; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowChanged; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowDeleting; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowDeleting; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public event AssociationRowChangeEventHandler AssociationRowDeleted; + public event CryptoKeyRowChangeEventHandler CryptoKeyRowDeleted; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public void AddAssociationRow(AssociationRow row) { + public void AddCryptoKeyRow(CryptoKeyRow row) { this.Rows.Add(row); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow AddAssociationRow(string DistinguishingFactor, string Handle, System.DateTime Expires, byte[] PrivateData) { - AssociationRow rowAssociationRow = ((AssociationRow)(this.NewRow())); + public CryptoKeyRow AddCryptoKeyRow(string Bucket, string Handle, System.DateTime ExpiresUtc, byte[] Secret) { + CryptoKeyRow rowCryptoKeyRow = ((CryptoKeyRow)(this.NewRow())); object[] columnValuesArray = new object[] { - DistinguishingFactor, + Bucket, Handle, - Expires, - PrivateData}; - rowAssociationRow.ItemArray = columnValuesArray; - this.Rows.Add(rowAssociationRow); - return rowAssociationRow; + ExpiresUtc, + Secret}; + rowCryptoKeyRow.ItemArray = columnValuesArray; + this.Rows.Add(rowCryptoKeyRow); + return rowCryptoKeyRow; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow FindByDistinguishingFactorHandle(string DistinguishingFactor, string Handle) { - return ((AssociationRow)(this.Rows.Find(new object[] { - DistinguishingFactor, + public CryptoKeyRow FindByBucketHandle(string Bucket, string Handle) { + return ((CryptoKeyRow)(this.Rows.Find(new object[] { + Bucket, Handle}))); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public override global::System.Data.DataTable Clone() { - AssociationDataTable cln = ((AssociationDataTable)(base.Clone())); + CryptoKeyDataTable cln = ((CryptoKeyDataTable)(base.Clone())); cln.InitVars(); return cln; } @@ -455,62 +455,63 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Data.DataTable CreateInstance() { - return new AssociationDataTable(); + return new CryptoKeyDataTable(); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] internal void InitVars() { - this.columnDistinguishingFactor = base.Columns["DistinguishingFactor"]; + this.columnBucket = base.Columns["Bucket"]; this.columnHandle = base.Columns["Handle"]; - this.columnExpires = base.Columns["Expires"]; - this.columnPrivateData = base.Columns["PrivateData"]; + this.columnExpiresUtc = base.Columns["ExpiresUtc"]; + this.columnSecret = base.Columns["Secret"]; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] private void InitClass() { - this.columnDistinguishingFactor = new global::System.Data.DataColumn("DistinguishingFactor", typeof(string), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnDistinguishingFactor); + this.columnBucket = new global::System.Data.DataColumn("Bucket", typeof(string), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnBucket); this.columnHandle = new global::System.Data.DataColumn("Handle", typeof(string), null, global::System.Data.MappingType.Element); base.Columns.Add(this.columnHandle); - this.columnExpires = new global::System.Data.DataColumn("Expires", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnExpires); - this.columnPrivateData = new global::System.Data.DataColumn("PrivateData", typeof(byte[]), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnPrivateData); + this.columnExpiresUtc = new global::System.Data.DataColumn("ExpiresUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnExpiresUtc); + this.columnSecret = new global::System.Data.DataColumn("Secret", typeof(byte[]), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnSecret); this.Constraints.Add(new global::System.Data.UniqueConstraint("PrimaryKey", new global::System.Data.DataColumn[] { - this.columnDistinguishingFactor, + this.columnBucket, this.columnHandle}, true)); - this.columnDistinguishingFactor.AllowDBNull = false; + this.columnBucket.AllowDBNull = false; this.columnHandle.AllowDBNull = false; - this.columnExpires.AllowDBNull = false; - this.columnPrivateData.AllowDBNull = false; + this.columnExpiresUtc.AllowDBNull = false; + this.columnExpiresUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; + this.columnSecret.AllowDBNull = false; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow NewAssociationRow() { - return ((AssociationRow)(this.NewRow())); + public CryptoKeyRow NewCryptoKeyRow() { + return ((CryptoKeyRow)(this.NewRow())); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Data.DataRow NewRowFromBuilder(global::System.Data.DataRowBuilder builder) { - return new AssociationRow(builder); + return new CryptoKeyRow(builder); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override global::System.Type GetRowType() { - return typeof(AssociationRow); + return typeof(CryptoKeyRow); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowChanged(global::System.Data.DataRowChangeEventArgs e) { base.OnRowChanged(e); - if ((this.AssociationRowChanged != null)) { - this.AssociationRowChanged(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowChanged != null)) { + this.CryptoKeyRowChanged(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -518,8 +519,8 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowChanging(global::System.Data.DataRowChangeEventArgs e) { base.OnRowChanging(e); - if ((this.AssociationRowChanging != null)) { - this.AssociationRowChanging(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowChanging != null)) { + this.CryptoKeyRowChanging(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -527,8 +528,8 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowDeleted(global::System.Data.DataRowChangeEventArgs e) { base.OnRowDeleted(e); - if ((this.AssociationRowDeleted != null)) { - this.AssociationRowDeleted(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowDeleted != null)) { + this.CryptoKeyRowDeleted(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } @@ -536,14 +537,14 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] protected override void OnRowDeleting(global::System.Data.DataRowChangeEventArgs e) { base.OnRowDeleting(e); - if ((this.AssociationRowDeleting != null)) { - this.AssociationRowDeleting(this, new AssociationRowChangeEvent(((AssociationRow)(e.Row)), e.Action)); + if ((this.CryptoKeyRowDeleting != null)) { + this.CryptoKeyRowDeleting(this, new CryptoKeyRowChangeEvent(((CryptoKeyRow)(e.Row)), e.Action)); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public void RemoveAssociationRow(AssociationRow row) { + public void RemoveCryptoKeyRow(CryptoKeyRow row) { this.Rows.Remove(row); } @@ -570,7 +571,7 @@ namespace OpenIdRelyingPartyWebForms.Code { type.Attributes.Add(attribute1); global::System.Xml.Schema.XmlSchemaAttribute attribute2 = new global::System.Xml.Schema.XmlSchemaAttribute(); attribute2.Name = "tableTypeName"; - attribute2.FixedValue = "AssociationDataTable"; + attribute2.FixedValue = "CryptoKeyDataTable"; type.Attributes.Add(attribute2); type.Particle = sequence; global::System.Xml.Schema.XmlSchema dsSchema = ds.GetSchemaSerializable(); @@ -622,9 +623,9 @@ namespace OpenIdRelyingPartyWebForms.Code { private global::System.Data.DataColumn columnCode; - private global::System.Data.DataColumn columnIssued; + private global::System.Data.DataColumn columnIssuedUtc; - private global::System.Data.DataColumn columnExpires; + private global::System.Data.DataColumn columnExpiresUtc; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] @@ -677,17 +678,17 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn IssuedColumn { + public global::System.Data.DataColumn IssuedUtcColumn { get { - return this.columnIssued; + return this.columnIssuedUtc; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public global::System.Data.DataColumn ExpiresColumn { + public global::System.Data.DataColumn ExpiresUtcColumn { get { - return this.columnExpires; + return this.columnExpiresUtc; } } @@ -728,13 +729,13 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public NonceRow AddNonceRow(string Context, string Code, System.DateTime Issued, System.DateTime Expires) { + public NonceRow AddNonceRow(string Context, string Code, System.DateTime IssuedUtc, System.DateTime ExpiresUtc) { NonceRow rowNonceRow = ((NonceRow)(this.NewRow())); object[] columnValuesArray = new object[] { Context, Code, - Issued, - Expires}; + IssuedUtc, + ExpiresUtc}; rowNonceRow.ItemArray = columnValuesArray; this.Rows.Add(rowNonceRow); return rowNonceRow; @@ -742,9 +743,9 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public NonceRow FindByIssuedCodeContext(System.DateTime Issued, string Code, string Context) { + public NonceRow FindByIssuedUtcCodeContext(System.DateTime IssuedUtc, string Code, string Context) { return ((NonceRow)(this.Rows.Find(new object[] { - Issued, + IssuedUtc, Code, Context}))); } @@ -768,8 +769,8 @@ namespace OpenIdRelyingPartyWebForms.Code { internal void InitVars() { this.columnContext = base.Columns["Context"]; this.columnCode = base.Columns["Code"]; - this.columnIssued = base.Columns["Issued"]; - this.columnExpires = base.Columns["Expires"]; + this.columnIssuedUtc = base.Columns["IssuedUtc"]; + this.columnExpiresUtc = base.Columns["ExpiresUtc"]; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -779,18 +780,20 @@ namespace OpenIdRelyingPartyWebForms.Code { base.Columns.Add(this.columnContext); this.columnCode = new global::System.Data.DataColumn("Code", typeof(string), null, global::System.Data.MappingType.Element); base.Columns.Add(this.columnCode); - this.columnIssued = new global::System.Data.DataColumn("Issued", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnIssued); - this.columnExpires = new global::System.Data.DataColumn("Expires", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); - base.Columns.Add(this.columnExpires); + this.columnIssuedUtc = new global::System.Data.DataColumn("IssuedUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnIssuedUtc); + this.columnExpiresUtc = new global::System.Data.DataColumn("ExpiresUtc", typeof(global::System.DateTime), null, global::System.Data.MappingType.Element); + base.Columns.Add(this.columnExpiresUtc); this.Constraints.Add(new global::System.Data.UniqueConstraint("Constraint1", new global::System.Data.DataColumn[] { - this.columnIssued, + this.columnIssuedUtc, this.columnCode, this.columnContext}, true)); this.columnContext.AllowDBNull = false; this.columnCode.AllowDBNull = false; - this.columnIssued.AllowDBNull = false; - this.columnExpires.AllowDBNull = false; + this.columnIssuedUtc.AllowDBNull = false; + this.columnIssuedUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; + this.columnExpiresUtc.AllowDBNull = false; + this.columnExpiresUtc.DateTimeMode = global::System.Data.DataSetDateTime.Utc; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -920,25 +923,25 @@ namespace OpenIdRelyingPartyWebForms.Code { /// <summary> ///Represents strongly named DataRow class. ///</summary> - public partial class AssociationRow : global::System.Data.DataRow { + public partial class CryptoKeyRow : global::System.Data.DataRow { - private AssociationDataTable tableAssociation; + private CryptoKeyDataTable tableCryptoKey; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - internal AssociationRow(global::System.Data.DataRowBuilder rb) : + internal CryptoKeyRow(global::System.Data.DataRowBuilder rb) : base(rb) { - this.tableAssociation = ((AssociationDataTable)(this.Table)); + this.tableCryptoKey = ((CryptoKeyDataTable)(this.Table)); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public string DistinguishingFactor { + public string Bucket { get { - return ((string)(this[this.tableAssociation.DistinguishingFactorColumn])); + return ((string)(this[this.tableCryptoKey.BucketColumn])); } set { - this[this.tableAssociation.DistinguishingFactorColumn] = value; + this[this.tableCryptoKey.BucketColumn] = value; } } @@ -946,32 +949,32 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] public string Handle { get { - return ((string)(this[this.tableAssociation.HandleColumn])); + return ((string)(this[this.tableCryptoKey.HandleColumn])); } set { - this[this.tableAssociation.HandleColumn] = value; + this[this.tableCryptoKey.HandleColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Expires { + public System.DateTime ExpiresUtc { get { - return ((global::System.DateTime)(this[this.tableAssociation.ExpiresColumn])); + return ((global::System.DateTime)(this[this.tableCryptoKey.ExpiresUtcColumn])); } set { - this[this.tableAssociation.ExpiresColumn] = value; + this[this.tableCryptoKey.ExpiresUtcColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public byte[] PrivateData { + public byte[] Secret { get { - return ((byte[])(this[this.tableAssociation.PrivateDataColumn])); + return ((byte[])(this[this.tableCryptoKey.SecretColumn])); } set { - this[this.tableAssociation.PrivateDataColumn] = value; + this[this.tableCryptoKey.SecretColumn] = value; } } } @@ -1014,23 +1017,23 @@ namespace OpenIdRelyingPartyWebForms.Code { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Issued { + public System.DateTime IssuedUtc { get { - return ((global::System.DateTime)(this[this.tableNonce.IssuedColumn])); + return ((global::System.DateTime)(this[this.tableNonce.IssuedUtcColumn])); } set { - this[this.tableNonce.IssuedColumn] = value; + this[this.tableNonce.IssuedUtcColumn] = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public System.DateTime Expires { + public System.DateTime ExpiresUtc { get { - return ((global::System.DateTime)(this[this.tableNonce.ExpiresColumn])); + return ((global::System.DateTime)(this[this.tableNonce.ExpiresUtcColumn])); } set { - this[this.tableNonce.ExpiresColumn] = value; + this[this.tableNonce.ExpiresUtcColumn] = value; } } } @@ -1039,22 +1042,22 @@ namespace OpenIdRelyingPartyWebForms.Code { ///Row event argument class ///</summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public class AssociationRowChangeEvent : global::System.EventArgs { + public class CryptoKeyRowChangeEvent : global::System.EventArgs { - private AssociationRow eventRow; + private CryptoKeyRow eventRow; private global::System.Data.DataRowAction eventAction; [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRowChangeEvent(AssociationRow row, global::System.Data.DataRowAction action) { + public CryptoKeyRowChangeEvent(CryptoKeyRow row, global::System.Data.DataRowAction action) { this.eventRow = row; this.eventAction = action; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] - public AssociationRow Row { + public CryptoKeyRow Row { get { return this.eventRow; } diff --git a/samples/OpenIdRelyingPartyWebForms/Web.config b/samples/OpenIdRelyingPartyWebForms/Web.config index 1f1842b..485f8dc 100644 --- a/samples/OpenIdRelyingPartyWebForms/Web.config +++ b/samples/OpenIdRelyingPartyWebForms/Web.config @@ -41,7 +41,7 @@ <!--<add type="DotNetOpenAuth.OpenId.Behaviors.GsaIcamProfile, DotNetOpenAuth" />--> </behaviors> <!-- Uncomment the following to activate the sample custom store. --> - <!--<store type="OpenIdRelyingPartyWebForms.CustomStore, OpenIdRelyingPartyWebForms" />--> + <!--<store type="OpenIdRelyingPartyWebForms.Code.CustomStore, OpenIdRelyingPartyWebForms" />--> </relyingParty> </openid> <messaging> |