summaryrefslogtreecommitdiffstats
path: root/src/OAuth/OAuthAuthorizationServer/Code
diff options
context:
space:
mode:
Diffstat (limited to 'src/OAuth/OAuthAuthorizationServer/Code')
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/Client.cs64
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml49
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml.layout50
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/DataClasses.designer.cs977
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs96
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/HttpHeaderAttribute.cs41
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs191
-rw-r--r--src/OAuth/OAuthAuthorizationServer/Code/Utilities.cs21
8 files changed, 1489 insertions, 0 deletions
diff --git a/src/OAuth/OAuthAuthorizationServer/Code/Client.cs b/src/OAuth/OAuthAuthorizationServer/Code/Client.cs
new file mode 100644
index 0000000..0013f27
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/Client.cs
@@ -0,0 +1,64 @@
+namespace OAuthAuthorizationServer.Code {
+ using System;
+ using System.Collections.Generic;
+
+ using DotNetOpenAuth.OAuth2;
+
+ /// <summary>
+ /// An OAuth 2.0 Client that has registered with this Authorization Server.
+ /// </summary>
+ public partial class Client : IClientDescription {
+ #region IConsumerDescription Members
+
+ /// <summary>
+ /// Gets the client secret.
+ /// </summary>
+ string IClientDescription.Secret {
+ get { return this.ClientSecret; }
+ }
+
+ /// <summary>
+ /// Gets the callback to use when an individual authorization request
+ /// does not include an explicit callback URI.
+ /// </summary>
+ /// <value>
+ /// An absolute URL; or <c>null</c> if none is registered.
+ /// </value>
+ Uri IClientDescription.DefaultCallback {
+ get { return string.IsNullOrEmpty(this.Callback) ? null : new Uri(this.Callback); }
+ }
+
+ /// <summary>
+ /// Gets the type of the client.
+ /// </summary>
+ ClientType IClientDescription.ClientType {
+ get { return (ClientType)this.ClientType; }
+ }
+
+ /// <summary>
+ /// Determines whether a callback URI included in a client's authorization request
+ /// is among those allowed callbacks for the registered client.
+ /// </summary>
+ /// <param name="callback">The absolute URI the client has requested the authorization result be received at.</param>
+ /// <returns>
+ /// <c>true</c> if the callback URL is allowable for this client; otherwise, <c>false</c>.
+ /// </returns>
+ bool IClientDescription.IsCallbackAllowed(Uri callback) {
+ if (string.IsNullOrEmpty(this.Callback)) {
+ // No callback rules have been set up for this client.
+ return true;
+ }
+
+ // In this sample, it's enough of a callback URL match if the scheme and host match.
+ // In a production app, it is advisable to require a match on the path as well.
+ Uri acceptableCallbackPattern = new Uri(this.Callback);
+ if (string.Equals(acceptableCallbackPattern.GetLeftPart(UriPartial.Authority), callback.GetLeftPart(UriPartial.Authority), StringComparison.Ordinal)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml
new file mode 100644
index 0000000..fe621c2
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?><Database Name="Database" EntityNamespace="OAuthAuthorizationServer.Code" Class="DataClassesDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
+ <Connection Mode="WebSettings" ConnectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True" SettingsObjectName="System.Configuration.ConfigurationManager.ConnectionStrings" SettingsPropertyName="DatabaseConnectionString" Provider="System.Data.SqlClient" />
+ <Table Name="dbo.[User]" Member="Users">
+ <Type Name="User">
+ <Column Name="UserId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
+ <Column Name="OpenIDClaimedIdentifier" Type="System.String" DbType="NVarChar(150) NOT NULL" CanBeNull="false" />
+ <Column Name="OpenIDFriendlyIdentifier" Type="System.String" DbType="NVarChar(150)" CanBeNull="true" />
+ <Association Name="User_ClientAuthorization" Member="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="UserId" OtherKey="UserId" Type="ClientAuthorization" />
+ </Type>
+ </Table>
+ <Table Name="dbo.Client" Member="Clients">
+ <Type Name="Client">
+ <Column Name="ClientId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
+ <Column Name="ClientIdentifier" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
+ <Column Name="ClientSecret" Type="System.String" DbType="NVarChar(50)" CanBeNull="true" />
+ <Column Name="Callback" Type="System.String" CanBeNull="true" />
+ <Column Name="Name" Type="System.String" CanBeNull="false" />
+ <Column Member="ClientType" Type="System.Int32" CanBeNull="false" />
+ <Association Name="Client_ClientAuthorization" Member="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="ClientId" OtherKey="ClientId" Type="ClientAuthorization" />
+ </Type>
+ </Table>
+ <Table Name="dbo.ClientAuthorization" Member="ClientAuthorizations">
+ <Type Name="ClientAuthorization">
+ <Column Name="AuthorizationId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
+ <Column Name="CreatedOnUtc" Storage="_IssueDate" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" />
+ <Column Name="ClientId" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+ <Column Name="UserId" Type="System.Int32" DbType="Int" CanBeNull="false" />
+ <Column Name="Scope" Type="System.String" DbType="nvarchar(MAX)" CanBeNull="false" />
+ <Column Name="ExpirationDateUtc" Type="System.DateTime" DbType="DateTime NULL" CanBeNull="true" />
+ <Association Name="Client_ClientAuthorization" Member="Client" ThisKey="ClientId" OtherKey="ClientId" Type="Client" IsForeignKey="true" DeleteRule="CASCADE" DeleteOnNull="true" />
+ <Association Name="User_ClientAuthorization" Member="User" ThisKey="UserId" OtherKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" />
+ </Type>
+ </Table>
+ <Table Name="dbo.Nonce" Member="Nonces">
+ <Type Name="Nonce">
+ <Column Name="Context" Type="System.String" IsPrimaryKey="true" CanBeNull="false" />
+ <Column Name="Code" Type="System.String" IsPrimaryKey="true" CanBeNull="false" />
+ <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/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml.layout b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml.layout
new file mode 100644
index 0000000..f4de725
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.dbml.layout
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ordesignerObjectsDiagram dslVersion="1.0.0.0" absoluteBounds="0, 0, 11, 8.5" name="DataClasses">
+ <DataContextMoniker Name="/DataClassesDataContext" />
+ <nestedChildShapes>
+ <classShape Id="696d2c69-040e-411d-9257-bb664b743834" absoluteBounds="0.5, 0.5, 2.125, 1.3862939453125">
+ <DataClassMoniker Name="/DataClassesDataContext/User" />
+ <nestedChildShapes>
+ <elementListCompartment Id="cd90aeff-476c-44a9-897f-a986e4a8305b" absoluteBounds="0.515, 0.96, 2.0949999999999998, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+ </nestedChildShapes>
+ </classShape>
+ <classShape Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" absoluteBounds="0.5, 3.5, 2, 1.7708968098958327">
+ <DataClassMoniker Name="/DataClassesDataContext/Client" />
+ <nestedChildShapes>
+ <elementListCompartment Id="464308c4-d112-4448-b0c9-d9b82fb0ca4e" absoluteBounds="0.515, 3.96, 1.9700000000000002, 1.2108968098958333" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+ </nestedChildShapes>
+ </classShape>
+ <classShape Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" absoluteBounds="3.5, 3.125, 2, 1.9631982421874996">
+ <DataClassMoniker Name="/DataClassesDataContext/ClientAuthorization" />
+ <nestedChildShapes>
+ <elementListCompartment Id="403126d0-3d2a-4af4-b0b8-c489a830bbd4" absoluteBounds="3.515, 3.585, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+ </nestedChildShapes>
+ </classShape>
+ <classShape Id="a63562a7-acf2-4ed9-9686-52a1ad85633e" absoluteBounds="1.375, 6.375, 2, 1.3862939453124996">
+ <DataClassMoniker Name="/DataClassesDataContext/Nonce" />
+ <nestedChildShapes>
+ <elementListCompartment Id="9e4514ef-bc7b-4179-88e6-05363bf6ee5e" absoluteBounds="1.39, 6.835, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+ </nestedChildShapes>
+ </classShape>
+ <associationConnector edgePoints="[(2.5 : 4.29409912109375); (3.5 : 4.29409912109375)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+ <AssociationMoniker Name="/DataClassesDataContext/Client/Client_ClientAuthorization" />
+ <nodes>
+ <classShapeMoniker Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" />
+ <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" />
+ </nodes>
+ </associationConnector>
+ <associationConnector edgePoints="[(2.59375 : 1.8862939453125); (2.59375 : 3.28125); (3.5 : 3.28125)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+ <AssociationMoniker Name="/DataClassesDataContext/User/User_ClientAuthorization" />
+ <nodes>
+ <classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" />
+ <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/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.designer.cs b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.designer.cs
new file mode 100644
index 0000000..c7af82a
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/DataClasses.designer.cs
@@ -0,0 +1,977 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.235
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OAuthAuthorizationServer.Code
+{
+ using System.Data.Linq;
+ using System.Data.Linq.Mapping;
+ using System.Data;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.ComponentModel;
+ using System;
+
+
+ [global::System.Data.Linq.Mapping.DatabaseAttribute(Name="Database")]
+ public partial class DataClassesDataContext : System.Data.Linq.DataContext
+ {
+
+ private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
+
+ #region Extensibility Method Definitions
+ partial void OnCreated();
+ partial void InsertUser(User instance);
+ partial void UpdateUser(User instance);
+ partial void DeleteUser(User instance);
+ partial void InsertClient(Client instance);
+ partial void UpdateClient(Client instance);
+ partial void DeleteClient(Client instance);
+ partial void InsertClientAuthorization(ClientAuthorization instance);
+ partial void UpdateClientAuthorization(ClientAuthorization instance);
+ partial void DeleteClientAuthorization(ClientAuthorization instance);
+ 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() :
+ base(global::System.Configuration.ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public DataClassesDataContext(string connection) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public DataClassesDataContext(System.Data.IDbConnection connection) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public DataClassesDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public DataClassesDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public System.Data.Linq.Table<User> Users
+ {
+ get
+ {
+ return this.GetTable<User>();
+ }
+ }
+
+ public System.Data.Linq.Table<Client> Clients
+ {
+ get
+ {
+ return this.GetTable<Client>();
+ }
+ }
+
+ public System.Data.Linq.Table<ClientAuthorization> ClientAuthorizations
+ {
+ get
+ {
+ return this.GetTable<ClientAuthorization>();
+ }
+ }
+
+ public System.Data.Linq.Table<Nonce> Nonces
+ {
+ get
+ {
+ 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]")]
+ public partial class User : INotifyPropertyChanging, INotifyPropertyChanged
+ {
+
+ private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty);
+
+ private int _UserId;
+
+ private string _OpenIDClaimedIdentifier;
+
+ private string _OpenIDFriendlyIdentifier;
+
+ private EntitySet<ClientAuthorization> _OAuthTokens;
+
+ #region Extensibility Method Definitions
+ partial void OnLoaded();
+ partial void OnValidate(System.Data.Linq.ChangeAction action);
+ partial void OnCreated();
+ partial void OnUserIdChanging(int value);
+ partial void OnUserIdChanged();
+ partial void OnOpenIDClaimedIdentifierChanging(string value);
+ partial void OnOpenIDClaimedIdentifierChanged();
+ partial void OnOpenIDFriendlyIdentifierChanging(string value);
+ partial void OnOpenIDFriendlyIdentifierChanged();
+ #endregion
+
+ public User()
+ {
+ this._OAuthTokens = new EntitySet<ClientAuthorization>(new Action<ClientAuthorization>(this.attach_OAuthTokens), new Action<ClientAuthorization>(this.detach_OAuthTokens));
+ OnCreated();
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
+ public int UserId
+ {
+ get
+ {
+ return this._UserId;
+ }
+ set
+ {
+ if ((this._UserId != value))
+ {
+ this.OnUserIdChanging(value);
+ this.SendPropertyChanging();
+ this._UserId = value;
+ this.SendPropertyChanged("UserId");
+ this.OnUserIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_OpenIDClaimedIdentifier", DbType="NVarChar(150) NOT NULL", CanBeNull=false)]
+ public string OpenIDClaimedIdentifier
+ {
+ get
+ {
+ return this._OpenIDClaimedIdentifier;
+ }
+ set
+ {
+ if ((this._OpenIDClaimedIdentifier != value))
+ {
+ this.OnOpenIDClaimedIdentifierChanging(value);
+ this.SendPropertyChanging();
+ this._OpenIDClaimedIdentifier = value;
+ this.SendPropertyChanged("OpenIDClaimedIdentifier");
+ this.OnOpenIDClaimedIdentifierChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_OpenIDFriendlyIdentifier", DbType="NVarChar(150)")]
+ public string OpenIDFriendlyIdentifier
+ {
+ get
+ {
+ return this._OpenIDFriendlyIdentifier;
+ }
+ set
+ {
+ if ((this._OpenIDFriendlyIdentifier != value))
+ {
+ this.OnOpenIDFriendlyIdentifierChanging(value);
+ this.SendPropertyChanging();
+ this._OpenIDFriendlyIdentifier = value;
+ this.SendPropertyChanged("OpenIDFriendlyIdentifier");
+ this.OnOpenIDFriendlyIdentifierChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_ClientAuthorization", Storage="_OAuthTokens", ThisKey="UserId", OtherKey="UserId")]
+ public EntitySet<ClientAuthorization> ClientAuthorizations
+ {
+ get
+ {
+ return this._OAuthTokens;
+ }
+ set
+ {
+ this._OAuthTokens.Assign(value);
+ }
+ }
+
+ 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));
+ }
+ }
+
+ private void attach_OAuthTokens(ClientAuthorization entity)
+ {
+ this.SendPropertyChanging();
+ entity.User = this;
+ }
+
+ private void detach_OAuthTokens(ClientAuthorization entity)
+ {
+ this.SendPropertyChanging();
+ entity.User = null;
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Client")]
+ public partial class Client : INotifyPropertyChanging, INotifyPropertyChanged
+ {
+
+ private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty);
+
+ private int _ClientId;
+
+ private string _ClientIdentifier;
+
+ private string _ClientSecret;
+
+ private string _Callback;
+
+ private string _Name;
+
+ private int _ClientType;
+
+ private EntitySet<ClientAuthorization> _OAuthTokens;
+
+ #region Extensibility Method Definitions
+ partial void OnLoaded();
+ partial void OnValidate(System.Data.Linq.ChangeAction action);
+ partial void OnCreated();
+ partial void OnClientIdChanging(int value);
+ partial void OnClientIdChanged();
+ partial void OnClientIdentifierChanging(string value);
+ partial void OnClientIdentifierChanged();
+ partial void OnClientSecretChanging(string value);
+ partial void OnClientSecretChanged();
+ partial void OnCallbackChanging(string value);
+ partial void OnCallbackChanged();
+ partial void OnNameChanging(string value);
+ partial void OnNameChanged();
+ partial void OnClientTypeChanging(int value);
+ partial void OnClientTypeChanged();
+ #endregion
+
+ public Client()
+ {
+ this._OAuthTokens = new EntitySet<ClientAuthorization>(new Action<ClientAuthorization>(this.attach_OAuthTokens), new Action<ClientAuthorization>(this.detach_OAuthTokens));
+ OnCreated();
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
+ public int ClientId
+ {
+ get
+ {
+ return this._ClientId;
+ }
+ set
+ {
+ if ((this._ClientId != value))
+ {
+ this.OnClientIdChanging(value);
+ this.SendPropertyChanging();
+ this._ClientId = value;
+ this.SendPropertyChanged("ClientId");
+ this.OnClientIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientIdentifier", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
+ public string ClientIdentifier
+ {
+ get
+ {
+ return this._ClientIdentifier;
+ }
+ set
+ {
+ if ((this._ClientIdentifier != value))
+ {
+ this.OnClientIdentifierChanging(value);
+ this.SendPropertyChanging();
+ this._ClientIdentifier = value;
+ this.SendPropertyChanged("ClientIdentifier");
+ this.OnClientIdentifierChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientSecret", DbType="NVarChar(50)")]
+ public string ClientSecret
+ {
+ get
+ {
+ return this._ClientSecret;
+ }
+ set
+ {
+ if ((this._ClientSecret != value))
+ {
+ this.OnClientSecretChanging(value);
+ this.SendPropertyChanging();
+ this._ClientSecret = value;
+ this.SendPropertyChanged("ClientSecret");
+ this.OnClientSecretChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Callback")]
+ public string Callback
+ {
+ get
+ {
+ return this._Callback;
+ }
+ set
+ {
+ if ((this._Callback != value))
+ {
+ this.OnCallbackChanging(value);
+ this.SendPropertyChanging();
+ this._Callback = value;
+ this.SendPropertyChanged("Callback");
+ this.OnCallbackChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Name", CanBeNull=false)]
+ public string Name
+ {
+ get
+ {
+ return this._Name;
+ }
+ set
+ {
+ if ((this._Name != value))
+ {
+ this.OnNameChanging(value);
+ this.SendPropertyChanging();
+ this._Name = value;
+ this.SendPropertyChanged("Name");
+ this.OnNameChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientType")]
+ public int ClientType
+ {
+ get
+ {
+ return this._ClientType;
+ }
+ set
+ {
+ if ((this._ClientType != value))
+ {
+ this.OnClientTypeChanging(value);
+ this.SendPropertyChanging();
+ this._ClientType = value;
+ this.SendPropertyChanged("ClientType");
+ this.OnClientTypeChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.AssociationAttribute(Name="Client_ClientAuthorization", Storage="_OAuthTokens", ThisKey="ClientId", OtherKey="ClientId")]
+ public EntitySet<ClientAuthorization> ClientAuthorizations
+ {
+ get
+ {
+ return this._OAuthTokens;
+ }
+ set
+ {
+ this._OAuthTokens.Assign(value);
+ }
+ }
+
+ 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));
+ }
+ }
+
+ private void attach_OAuthTokens(ClientAuthorization entity)
+ {
+ this.SendPropertyChanging();
+ entity.Client = this;
+ }
+
+ private void detach_OAuthTokens(ClientAuthorization entity)
+ {
+ this.SendPropertyChanging();
+ entity.Client = null;
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ClientAuthorization")]
+ public partial class ClientAuthorization : INotifyPropertyChanging, INotifyPropertyChanged
+ {
+
+ private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty);
+
+ private int _AuthorizationId;
+
+ private System.DateTime _IssueDate;
+
+ private int _ClientId;
+
+ private int _UserId;
+
+ private string _Scope;
+
+ private System.Nullable<System.DateTime> _ExpirationDateUtc;
+
+ private EntityRef<Client> _Client;
+
+ private EntityRef<User> _User;
+
+ #region Extensibility Method Definitions
+ partial void OnLoaded();
+ partial void OnValidate(System.Data.Linq.ChangeAction action);
+ partial void OnCreated();
+ partial void OnAuthorizationIdChanging(int value);
+ partial void OnAuthorizationIdChanged();
+ partial void OnCreatedOnUtcChanging(System.DateTime value);
+ partial void OnCreatedOnUtcChanged();
+ partial void OnClientIdChanging(int value);
+ partial void OnClientIdChanged();
+ partial void OnUserIdChanging(int value);
+ partial void OnUserIdChanged();
+ partial void OnScopeChanging(string value);
+ partial void OnScopeChanged();
+ partial void OnExpirationDateUtcChanging(System.Nullable<System.DateTime> value);
+ partial void OnExpirationDateUtcChanged();
+ #endregion
+
+ public ClientAuthorization()
+ {
+ this._Client = default(EntityRef<Client>);
+ this._User = default(EntityRef<User>);
+ OnCreated();
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AuthorizationId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
+ public int AuthorizationId
+ {
+ get
+ {
+ return this._AuthorizationId;
+ }
+ set
+ {
+ if ((this._AuthorizationId != value))
+ {
+ this.OnAuthorizationIdChanging(value);
+ this.SendPropertyChanging();
+ this._AuthorizationId = value;
+ this.SendPropertyChanged("AuthorizationId");
+ this.OnAuthorizationIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_IssueDate", DbType="DateTime NOT NULL")]
+ public System.DateTime CreatedOnUtc
+ {
+ get
+ {
+ return this._IssueDate;
+ }
+ set
+ {
+ if ((this._IssueDate != value))
+ {
+ this.OnCreatedOnUtcChanging(value);
+ this.SendPropertyChanging();
+ this._IssueDate = value;
+ this.SendPropertyChanged("CreatedOnUtc");
+ this.OnCreatedOnUtcChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientId", DbType="Int NOT NULL")]
+ public int ClientId
+ {
+ get
+ {
+ return this._ClientId;
+ }
+ set
+ {
+ if ((this._ClientId != value))
+ {
+ if (this._Client.HasLoadedOrAssignedValue)
+ {
+ throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+ }
+ this.OnClientIdChanging(value);
+ this.SendPropertyChanging();
+ this._ClientId = value;
+ this.SendPropertyChanged("ClientId");
+ this.OnClientIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="Int")]
+ public int UserId
+ {
+ get
+ {
+ return this._UserId;
+ }
+ set
+ {
+ if ((this._UserId != value))
+ {
+ if (this._User.HasLoadedOrAssignedValue)
+ {
+ throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+ }
+ this.OnUserIdChanging(value);
+ this.SendPropertyChanging();
+ this._UserId = value;
+ this.SendPropertyChanged("UserId");
+ this.OnUserIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Scope", DbType="nvarchar(MAX)", CanBeNull=false)]
+ public string Scope
+ {
+ get
+ {
+ return this._Scope;
+ }
+ set
+ {
+ if ((this._Scope != value))
+ {
+ this.OnScopeChanging(value);
+ this.SendPropertyChanging();
+ this._Scope = value;
+ this.SendPropertyChanged("Scope");
+ this.OnScopeChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExpirationDateUtc", DbType="DateTime NULL")]
+ public System.Nullable<System.DateTime> ExpirationDateUtc
+ {
+ get
+ {
+ return this._ExpirationDateUtc;
+ }
+ set
+ {
+ if ((this._ExpirationDateUtc != value))
+ {
+ this.OnExpirationDateUtcChanging(value);
+ this.SendPropertyChanging();
+ this._ExpirationDateUtc = value;
+ this.SendPropertyChanged("ExpirationDateUtc");
+ this.OnExpirationDateUtcChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.AssociationAttribute(Name="Client_ClientAuthorization", Storage="_Client", ThisKey="ClientId", OtherKey="ClientId", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")]
+ public Client Client
+ {
+ get
+ {
+ return this._Client.Entity;
+ }
+ set
+ {
+ Client previousValue = this._Client.Entity;
+ if (((previousValue != value)
+ || (this._Client.HasLoadedOrAssignedValue == false)))
+ {
+ this.SendPropertyChanging();
+ if ((previousValue != null))
+ {
+ this._Client.Entity = null;
+ previousValue.ClientAuthorizations.Remove(this);
+ }
+ this._Client.Entity = value;
+ if ((value != null))
+ {
+ value.ClientAuthorizations.Add(this);
+ this._ClientId = value.ClientId;
+ }
+ else
+ {
+ this._ClientId = default(int);
+ }
+ this.SendPropertyChanged("Client");
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_ClientAuthorization", Storage="_User", ThisKey="UserId", OtherKey="UserId", IsForeignKey=true, DeleteRule="CASCADE")]
+ public User User
+ {
+ get
+ {
+ return this._User.Entity;
+ }
+ set
+ {
+ User previousValue = this._User.Entity;
+ if (((previousValue != value)
+ || (this._User.HasLoadedOrAssignedValue == false)))
+ {
+ this.SendPropertyChanging();
+ if ((previousValue != null))
+ {
+ this._User.Entity = null;
+ previousValue.ClientAuthorizations.Remove(this);
+ }
+ this._User.Entity = value;
+ if ((value != null))
+ {
+ value.ClientAuthorizations.Add(this);
+ this._UserId = value.UserId;
+ }
+ else
+ {
+ this._UserId = default(int);
+ }
+ this.SendPropertyChanged("User");
+ }
+ }
+ }
+
+ 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));
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Nonce")]
+ public partial class Nonce : INotifyPropertyChanging, INotifyPropertyChanged
+ {
+
+ private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty);
+
+ private string _Context;
+
+ private string _Code;
+
+ private System.DateTime _Timestamp;
+
+ #region Extensibility Method Definitions
+ partial void OnLoaded();
+ partial void OnValidate(System.Data.Linq.ChangeAction action);
+ partial void OnCreated();
+ partial void OnContextChanging(string value);
+ partial void OnContextChanged();
+ partial void OnCodeChanging(string value);
+ partial void OnCodeChanged();
+ partial void OnTimestampChanging(System.DateTime value);
+ partial void OnTimestampChanged();
+ #endregion
+
+ public Nonce()
+ {
+ OnCreated();
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Context", CanBeNull=false, IsPrimaryKey=true)]
+ public string Context
+ {
+ get
+ {
+ return this._Context;
+ }
+ set
+ {
+ if ((this._Context != value))
+ {
+ this.OnContextChanging(value);
+ this.SendPropertyChanging();
+ this._Context = value;
+ this.SendPropertyChanged("Context");
+ this.OnContextChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Code", CanBeNull=false, IsPrimaryKey=true)]
+ public string Code
+ {
+ get
+ {
+ return this._Code;
+ }
+ set
+ {
+ if ((this._Code != value))
+ {
+ this.OnCodeChanging(value);
+ this.SendPropertyChanging();
+ this._Code = value;
+ this.SendPropertyChanged("Code");
+ this.OnCodeChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Timestamp", IsPrimaryKey=true)]
+ public System.DateTime Timestamp
+ {
+ get
+ {
+ return this._Timestamp;
+ }
+ set
+ {
+ if ((this._Timestamp != value))
+ {
+ this.OnTimestampChanging(value);
+ this.SendPropertyChanging();
+ this._Timestamp = value;
+ this.SendPropertyChanged("Timestamp");
+ this.OnTimestampChanged();
+ }
+ }
+ }
+
+ 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));
+ }
+ }
+ }
+
+ [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/src/OAuth/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs b/src/OAuth/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs
new file mode 100644
index 0000000..0a1d8af
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/DatabaseKeyNonceStore.cs
@@ -0,0 +1,96 @@
+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 DatabaseKeyNonceStore : INonceStore, ICryptoKeyStore {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DatabaseKeyNonceStore"/> class.
+ /// </summary>
+ public DatabaseKeyNonceStore() {
+ }
+
+ #region INonceStore Members
+
+ /// <summary>
+ /// Stores a given nonce and timestamp.
+ /// </summary>
+ /// <param name="context">The context, or namespace, within which the
+ /// <paramref name="nonce"/> must be unique.
+ /// 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="timestampUtc">The UTC timestamp that together with the nonce string make it unique
+ /// within the given <paramref name="context"/>.
+ /// The timestamp may also be used by the data store to clear out old nonces.</param>
+ /// <returns>
+ /// True if the context+nonce+timestamp (combination) was not previously in the database.
+ /// False if the nonce was stored previously with the same timestamp and context.
+ /// </returns>
+ /// <remarks>
+ /// The nonce must be stored for no less than the maximum time window a message may
+ /// be processed within before being discarded as an expired message.
+ /// This maximum message age can be looked up via the
+ /// <see cref="DotNetOpenAuth.Configuration.MessagingElement.MaximumMessageLifetime"/>
+ /// property, accessible via the <see cref="DotNetOpenAuth.Configuration.DotNetOpenAuthSection.Configuration"/>
+ /// property.
+ /// </remarks>
+ public bool StoreNonce(string context, string nonce, DateTime timestampUtc) {
+ MvcApplication.DataContext.Nonces.InsertOnSubmit(new Nonce { Context = context, Code = nonce, Timestamp = timestampUtc });
+ try {
+ MvcApplication.DataContext.SubmitChanges();
+ return true;
+ } catch (System.Data.Linq.DuplicateKeyException) {
+ return false;
+ } catch (SqlException) {
+ return false;
+ }
+ }
+
+ #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/src/OAuth/OAuthAuthorizationServer/Code/HttpHeaderAttribute.cs b/src/OAuth/OAuthAuthorizationServer/Code/HttpHeaderAttribute.cs
new file mode 100644
index 0000000..d3201c2
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/HttpHeaderAttribute.cs
@@ -0,0 +1,41 @@
+namespace OAuthAuthorizationServer.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using System.Web.Mvc;
+
+ /// <summary>
+ /// Represents an attribute that is used to add HTTP Headers to a Controller Action response.
+ /// </summary>
+ public class HttpHeaderAttribute : ActionFilterAttribute {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HttpHeaderAttribute"/> class.
+ /// </summary>
+ /// <param name="name">The HTTP header name.</param>
+ /// <param name="value">The HTTP header value.</param>
+ public HttpHeaderAttribute(string name, string value) {
+ this.Name = name;
+ this.Value = value;
+ }
+
+ /// <summary>
+ /// Gets or sets the name of the HTTP Header.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the value of the HTTP Header.
+ /// </summary>
+ public string Value { get; set; }
+
+ /// <summary>
+ /// Called by the MVC framework after the action result executes.
+ /// </summary>
+ /// <param name="filterContext">The filter context.</param>
+ public override void OnResultExecuted(ResultExecutedContext filterContext) {
+ filterContext.HttpContext.Response.AppendHeader(this.Name, this.Value);
+ base.OnResultExecuted(filterContext);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/OAuth/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs b/src/OAuth/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs
new file mode 100644
index 0000000..b837d4c
--- /dev/null
+++ b/src/OAuth/OAuthAuthorizationServer/Code/OAuth2AuthorizationServer.cs
@@ -0,0 +1,191 @@
+namespace OAuthAuthorizationServer.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth2;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ internal class OAuth2AuthorizationServer : IAuthorizationServer {
+ private static readonly RSACryptoServiceProvider AsymmetricTokenSigningPrivateKey = CreateRSA();
+
+#if SAMPLESONLY
+ /// <summary>
+ /// This is the FOR SAMPLE ONLY hard-coded public key of the complementary OAuthResourceServer sample.
+ /// </summary>
+ /// <remarks>
+ /// In a real app, the authorization server would need to determine which resource server the access token needs to be encoded for
+ /// based on the authorization request. It would then need to look up the public key for that resource server and use that in
+ /// preparing the access token for the client to use against that resource server.
+ /// </remarks>
+ private static readonly RSAParameters ResourceServerEncryptionPublicKey = new RSAParameters {
+ Exponent = new byte[] { 1, 0, 1 },
+ Modulus = new byte[] { 166, 175, 117, 169, 211, 251, 45, 215, 55, 53, 202, 65, 153, 155, 92, 219, 235, 243, 61, 170, 101, 250, 221, 214, 239, 175, 238, 175, 239, 20, 144, 72, 227, 221, 4, 219, 32, 225, 101, 96, 18, 33, 117, 176, 110, 123, 109, 23, 29, 85, 93, 50, 129, 163, 113, 57, 122, 212, 141, 145, 17, 31, 67, 165, 181, 91, 117, 23, 138, 251, 198, 132, 188, 213, 10, 157, 116, 229, 48, 168, 8, 127, 28, 156, 239, 124, 117, 36, 232, 100, 222, 23, 52, 186, 239, 5, 63, 207, 185, 16, 137, 73, 137, 147, 252, 71, 9, 239, 113, 27, 88, 255, 91, 56, 192, 142, 210, 21, 34, 81, 204, 239, 57, 60, 140, 249, 15, 101 },
+ };
+#else
+ [Obsolete("You must use a real key for a real app.", true)]
+ private static readonly RSAParameters ResourceServerEncryptionPublicKey;
+#endif
+
+ #region Implementation of IAuthorizationServer
+
+ public ICryptoKeyStore CryptoKeyStore {
+ get { return MvcApplication.KeyNonceStore; }
+ }
+
+ public INonceStore VerificationCodeNonceStore {
+ get { return MvcApplication.KeyNonceStore; }
+ }
+
+ public RSACryptoServiceProvider AccessTokenSigningKey {
+ get { return AsymmetricTokenSigningPrivateKey; }
+ }
+
+ public TimeSpan GetAccessTokenLifetime(IAccessTokenRequest accessTokenRequestMessage) {
+ // Just for the sake of the sample, we use a short-lived token. This can be useful to mitigate the security risks
+ // of access tokens that are used over standard HTTP.
+ // But this is just the lifetime of the access token. The client can still renew it using their refresh token until
+ // the authorization itself expires.
+ TimeSpan lifetime = TimeSpan.FromMinutes(2);
+
+ // Also take into account the remaining life of the authorization and artificially shorten the access token's lifetime
+ // to account for that if necessary.
+ //// TODO: code here
+
+ return lifetime;
+ }
+
+ public RSACryptoServiceProvider GetResourceServerEncryptionKey(IAccessTokenRequest accessTokenRequestMessage) {
+ var resourceServerEncryptionKey = new RSACryptoServiceProvider();
+
+ // For this sample, we assume just one resource server.
+ // If this authorization server needs to mint access tokens for more than one resource server,
+ // we'd look at the request message passed to us and decide which public key to return.
+ resourceServerEncryptionKey.ImportParameters(ResourceServerEncryptionPublicKey);
+
+ return resourceServerEncryptionKey;
+ }
+
+ public IClientDescription GetClient(string clientIdentifier) {
+ var consumerRow = MvcApplication.DataContext.Clients.SingleOrDefault(
+ consumerCandidate => consumerCandidate.ClientIdentifier == clientIdentifier);
+ if (consumerRow == null) {
+ throw new ArgumentOutOfRangeException("clientIdentifier");
+ }
+
+ return consumerRow;
+ }
+
+ public bool IsAuthorizationValid(IAuthorizationDescription authorization) {
+ return this.IsAuthorizationValid(authorization.Scope, authorization.ClientIdentifier, authorization.UtcIssued, authorization.User);
+ }
+
+ public bool IsResourceOwnerCredentialValid(string userName, string password) {
+ // This web site delegates user authentication to OpenID Providers, and as such no users have local passwords with this server.
+ throw new NotSupportedException();
+ }
+
+ #endregion
+
+ public bool CanBeAutoApproved(EndUserAuthorizationRequest authorizationRequest) {
+ if (authorizationRequest == null) {
+ throw new ArgumentNullException("authorizationRequest");
+ }
+
+ // 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 arbitrary clients to masquarade as an approved client
+ // and obtain unauthorized access to user data.
+ if (authorizationRequest.ResponseType == EndUserAuthorizationResponseType.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);
+ if (!string.IsNullOrEmpty(requestingClient.ClientSecret)) {
+ return this.IsAuthorizationValid(
+ authorizationRequest.Scope,
+ authorizationRequest.ClientIdentifier,
+ DateTime.UtcNow,
+ HttpContext.Current.User.Identity.Name);
+ }
+ }
+
+ // Default to not auto-approving.
+ 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 static RSACryptoServiceProvider CreateRSA() {
+ var rsa = new RSACryptoServiceProvider();
+ rsa.ImportParameters(CreateRSAKey());
+ return rsa;
+ }
+
+ 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;
+
+ if (!grantedScopeStrings.Any()) {
+ // No granted authorizations prior to the issuance of this token, so it must have been revoked.
+ // Even if later authorizations restore this client's ability to call in, we can't allow
+ // access tokens issued before the re-authorization because the revoked authorization should
+ // effectively and permanently revoke all access and refresh tokens.
+ return false;
+ }
+
+ var grantedScopes = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ foreach (string scope in grantedScopeStrings) {
+ grantedScopes.UnionWith(OAuthUtilities.SplitScopes(scope));
+ }
+
+ return requestedScopes.IsSubsetOf(grantedScopes);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/OAuth/OAuthAuthorizationServer/Code/Utilities.cs b/src/OAuth/OAuthAuthorizationServer/Code/Utilities.cs
new file mode 100644
index 0000000..c9109bd
--- /dev/null
+++ b/src/OAuth/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