diff options
Diffstat (limited to 'src/OAuth/OAuthServiceProvider/Code')
17 files changed, 2085 insertions, 0 deletions
diff --git a/src/OAuth/OAuthServiceProvider/Code/Constants.cs b/src/OAuth/OAuthServiceProvider/Code/Constants.cs new file mode 100644 index 0000000..3e629f0 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/Constants.cs @@ -0,0 +1,32 @@ +namespace OAuthServiceProvider.Code { + using System; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// Service Provider definitions. + /// </summary> + public static class Constants { + public static Uri WebRootUrl { get; set; } + + public static ServiceProviderDescription SelfDescription { + get { + ServiceProviderDescription description = new ServiceProviderDescription { + AccessTokenEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest), + RequestTokenEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { + new HmacSha1SigningBindingElement(), + }, + }; + + return description; + } + } + + public static ServiceProvider CreateServiceProvider() { + return new ServiceProvider(SelfDescription, Global.TokenManager, Global.NonceStore); + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/CustomOAuthTypeProvider.cs b/src/OAuth/OAuthServiceProvider/Code/CustomOAuthTypeProvider.cs new file mode 100644 index 0000000..67da17c --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/CustomOAuthTypeProvider.cs @@ -0,0 +1,34 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth.ChannelElements; + using DotNetOpenAuth.OAuth.Messages; + + /// <summary> + /// A custom class that will cause the OAuth library to use our custom message types + /// where we have them. + /// </summary> + public class CustomOAuthMessageFactory : OAuthServiceProviderMessageFactory { + /// <summary> + /// Initializes a new instance of the <see cref="CustomOAuthMessageFactory"/> class. + /// </summary> + /// <param name="tokenManager">The token manager instance to use.</param> + public CustomOAuthMessageFactory(IServiceProviderTokenManager tokenManager) + : base(tokenManager) { + } + + public override IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { + var message = base.GetNewRequestMessage(recipient, fields); + + // inject our own type here to replace the standard one + if (message is UnauthorizedTokenRequest) { + message = new RequestScopedTokenMessage(recipient, message.Version); + } + + return message; + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml b/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml new file mode 100644 index 0000000..5522ec8 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?><Database Name="Database" EntityNamespace="OAuthServiceProvider.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" /> + <Column Name="FullName" Type="System.String" DbType="NVarChar(150)" CanBeNull="false" /> + <Column Name="Age" Type="System.Int32" DbType="int" CanBeNull="true" /> + <Association Name="User_FavoriteSite" Member="FavoriteSites" ThisKey="UserId" OtherKey="UserId" Type="FavoriteSite" /> + <Association Name="User_OAuthToken" Member="OAuthTokens" ThisKey="UserId" OtherKey="UserId" Type="OAuthToken" /> + </Type> + </Table> + <Table Name="dbo.FavoriteSite" Member="FavoriteSites"> + <Type Name="FavoriteSite"> + <Column Name="FavoriteSiteId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> + <Column Name="UserId" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" /> + <Column Name="SiteUrl" Type="System.String" DbType="NVarChar(255) NOT NULL" CanBeNull="false" /> + <Association Name="User_FavoriteSite" Member="User" ThisKey="UserId" OtherKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" DeleteOnNull="true" /> + </Type> + </Table> + <Table Name="dbo.OAuthConsumer" Member="OAuthConsumers"> + <Type Name="OAuthConsumer"> + <Column Name="ConsumerId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> + <Column Name="ConsumerKey" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="ConsumerSecret" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="Callback" Type="System.String" CanBeNull="true" /> + <Column Name="VerificationCodeFormat" Type="DotNetOpenAuth.OAuth.VerificationCodeFormat" CanBeNull="false" /> + <Column Name="VerificationCodeLength" Type="System.Int32" CanBeNull="false" /> + <Association Name="OAuthConsumer_OAuthToken" Member="OAuthTokens" ThisKey="ConsumerId" OtherKey="ConsumerId" Type="OAuthToken" /> + </Type> + </Table> + <Table Name="dbo.OAuthToken" Member="OAuthTokens"> + <Type Name="OAuthToken"> + <Column Name="TokenId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> + <Column Name="Token" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="TokenSecret" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="State" Type="OAuthServiceProvider.Code.TokenAuthorizationState" DbType="INT NOT NULL" CanBeNull="false" /> + <Column Name="IssueDate" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> + <Column Name="ConsumerId" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" /> + <Column Name="UserId" Type="System.Int32" DbType="Int" CanBeNull="true" /> + <Column Name="Scope" Type="System.String" DbType="nvarchar(MAX)" CanBeNull="false" /> + <Column Name="RequestTokenVerifier" Type="System.String" CanBeNull="true" /> + <Column Name="RequestTokenCallback" Type="System.String" CanBeNull="true" /> + <Column Name="ConsumerVersion" Type="System.String" CanBeNull="true" /> + <Association Name="OAuthConsumer_OAuthToken" Member="OAuthConsumer" ThisKey="ConsumerId" OtherKey="ConsumerId" Type="OAuthConsumer" IsForeignKey="true" DeleteRule="CASCADE" DeleteOnNull="true" /> + <Association Name="User_OAuthToken" Member="User" ThisKey="UserId" OtherKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" /> + </Type> + </Table> + <Table Name="" Member="Nonces"> + <Type Name="Nonce"> + <Column Member="Context" Type="System.String" IsPrimaryKey="true" CanBeNull="false" /> + <Column Member="Code" Type="System.String" IsPrimaryKey="true" CanBeNull="false" /> + <Column Member="Timestamp" Type="System.DateTime" IsPrimaryKey="true" CanBeNull="false" /> + </Type> + </Table> +</Database>
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml.layout b/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml.layout new file mode 100644 index 0000000..9b80443 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/DataClasses.dbml.layout @@ -0,0 +1,57 @@ +<?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.7708968098958331"> + <DataClassMoniker Name="/DataClassesDataContext/User" /> + <nestedChildShapes> + <elementListCompartment Id="cd90aeff-476c-44a9-897f-a986e4a8305b" absoluteBounds="0.515, 0.96, 2.0949999999999998, 1.2108968098958333" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <classShape Id="8a79b099-7f87-4766-907a-db2c3e1b5716" absoluteBounds="3.5, 0.625, 2, 1.3862939453125005"> + <DataClassMoniker Name="/DataClassesDataContext/FavoriteSite" /> + <nestedChildShapes> + <elementListCompartment Id="eba736b9-f9ec-484b-8083-c77155a49e4e" absoluteBounds="3.515, 1.085, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <classShape Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" absoluteBounds="0.625, 3.25, 2, 1.9631982421874996"> + <DataClassMoniker Name="/DataClassesDataContext/OAuthConsumer" /> + <nestedChildShapes> + <elementListCompartment Id="464308c4-d112-4448-b0c9-d9b82fb0ca4e" absoluteBounds="0.64, 3.71, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <classShape Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" absoluteBounds="3.5, 3.125, 2, 2.9247054036458326"> + <DataClassMoniker Name="/DataClassesDataContext/OAuthToken" /> + <nestedChildShapes> + <elementListCompartment Id="403126d0-3d2a-4af4-b0b8-c489a830bbd4" absoluteBounds="3.515, 3.585, 1.9700000000000002, 2.364705403645833" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <associationConnector edgePoints="[(2.625 : 1.31814697265625); (3.5 : 1.31814697265625)]" fixedFrom="NotFixed" fixedTo="NotFixed"> + <AssociationMoniker Name="/DataClassesDataContext/User/User_FavoriteSite" /> + <nodes> + <classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" /> + <classShapeMoniker Id="8a79b099-7f87-4766-907a-db2c3e1b5716" /> + </nodes> + </associationConnector> + <associationConnector edgePoints="[(2.625 : 4.23159912109375); (3.5 : 4.23159912109375)]" fixedFrom="NotFixed" fixedTo="NotFixed"> + <AssociationMoniker Name="/DataClassesDataContext/OAuthConsumer/OAuthConsumer_OAuthToken" /> + <nodes> + <classShapeMoniker Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" /> + <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> + </nodes> + </associationConnector> + <associationConnector edgePoints="[(0.53125 : 2.27089680989583); (0.53125 : 5.66270182291667); (3.5 : 5.66270182291667)]" fixedFrom="NotFixed" fixedTo="NotFixed"> + <AssociationMoniker Name="/DataClassesDataContext/User/User_OAuthToken" /> + <nodes> + <classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" /> + <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> + </nodes> + </associationConnector> + <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> + </nestedChildShapes> +</ordesignerObjectsDiagram>
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/DataClasses.designer.cs b/src/OAuth/OAuthServiceProvider/Code/DataClasses.designer.cs new file mode 100644 index 0000000..b7d291c --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/DataClasses.designer.cs @@ -0,0 +1,1190 @@ +#pragma warning disable 1591 +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OAuthServiceProvider.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 InsertFavoriteSite(FavoriteSite instance); + partial void UpdateFavoriteSite(FavoriteSite instance); + partial void DeleteFavoriteSite(FavoriteSite instance); + partial void InsertOAuthConsumer(OAuthConsumer instance); + partial void UpdateOAuthConsumer(OAuthConsumer instance); + partial void DeleteOAuthConsumer(OAuthConsumer instance); + partial void InsertOAuthToken(OAuthToken instance); + partial void UpdateOAuthToken(OAuthToken instance); + partial void DeleteOAuthToken(OAuthToken instance); + partial void InsertNonce(Nonce instance); + partial void UpdateNonce(Nonce instance); + partial void DeleteNonce(Nonce 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<FavoriteSite> FavoriteSites + { + get + { + return this.GetTable<FavoriteSite>(); + } + } + + public System.Data.Linq.Table<OAuthConsumer> OAuthConsumers + { + get + { + return this.GetTable<OAuthConsumer>(); + } + } + + public System.Data.Linq.Table<OAuthToken> OAuthTokens + { + get + { + return this.GetTable<OAuthToken>(); + } + } + + public System.Data.Linq.Table<Nonce> Nonces + { + get + { + return this.GetTable<Nonce>(); + } + } + } + + [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 string _FullName; + + private System.Nullable<int> _Age; + + private EntitySet<FavoriteSite> _FavoriteSites; + + private EntitySet<OAuthToken> _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(); + partial void OnFullNameChanging(string value); + partial void OnFullNameChanged(); + partial void OnAgeChanging(System.Nullable<int> value); + partial void OnAgeChanged(); + #endregion + + public User() + { + this._FavoriteSites = new EntitySet<FavoriteSite>(new Action<FavoriteSite>(this.attach_FavoriteSites), new Action<FavoriteSite>(this.detach_FavoriteSites)); + this._OAuthTokens = new EntitySet<OAuthToken>(new Action<OAuthToken>(this.attach_OAuthTokens), new Action<OAuthToken>(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.ColumnAttribute(Storage="_FullName", DbType="NVarChar(150)", CanBeNull=false)] + public string FullName + { + get + { + return this._FullName; + } + set + { + if ((this._FullName != value)) + { + this.OnFullNameChanging(value); + this.SendPropertyChanging(); + this._FullName = value; + this.SendPropertyChanged("FullName"); + this.OnFullNameChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Age", DbType="int")] + public System.Nullable<int> Age + { + get + { + return this._Age; + } + set + { + if ((this._Age != value)) + { + this.OnAgeChanging(value); + this.SendPropertyChanging(); + this._Age = value; + this.SendPropertyChanged("Age"); + this.OnAgeChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_FavoriteSite", Storage="_FavoriteSites", ThisKey="UserId", OtherKey="UserId")] + public EntitySet<FavoriteSite> FavoriteSites + { + get + { + return this._FavoriteSites; + } + set + { + this._FavoriteSites.Assign(value); + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_OAuthToken", Storage="_OAuthTokens", ThisKey="UserId", OtherKey="UserId")] + public EntitySet<OAuthToken> OAuthTokens + { + 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_FavoriteSites(FavoriteSite entity) + { + this.SendPropertyChanging(); + entity.User = this; + } + + private void detach_FavoriteSites(FavoriteSite entity) + { + this.SendPropertyChanging(); + entity.User = null; + } + + private void attach_OAuthTokens(OAuthToken entity) + { + this.SendPropertyChanging(); + entity.User = this; + } + + private void detach_OAuthTokens(OAuthToken entity) + { + this.SendPropertyChanging(); + entity.User = null; + } + } + + [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.FavoriteSite")] + public partial class FavoriteSite : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty); + + private int _FavoriteSiteId; + + private int _UserId; + + private string _SiteUrl; + + private EntityRef<User> _User; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnFavoriteSiteIdChanging(int value); + partial void OnFavoriteSiteIdChanged(); + partial void OnUserIdChanging(int value); + partial void OnUserIdChanged(); + partial void OnSiteUrlChanging(string value); + partial void OnSiteUrlChanged(); + #endregion + + public FavoriteSite() + { + this._User = default(EntityRef<User>); + OnCreated(); + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_FavoriteSiteId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + public int FavoriteSiteId + { + get + { + return this._FavoriteSiteId; + } + set + { + if ((this._FavoriteSiteId != value)) + { + this.OnFavoriteSiteIdChanging(value); + this.SendPropertyChanging(); + this._FavoriteSiteId = value; + this.SendPropertyChanged("FavoriteSiteId"); + this.OnFavoriteSiteIdChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="Int NOT NULL")] + 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="_SiteUrl", DbType="NVarChar(255) NOT NULL", CanBeNull=false)] + public string SiteUrl + { + get + { + return this._SiteUrl; + } + set + { + if ((this._SiteUrl != value)) + { + this.OnSiteUrlChanging(value); + this.SendPropertyChanging(); + this._SiteUrl = value; + this.SendPropertyChanged("SiteUrl"); + this.OnSiteUrlChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_FavoriteSite", Storage="_User", ThisKey="UserId", OtherKey="UserId", IsForeignKey=true, DeleteOnNull=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.FavoriteSites.Remove(this); + } + this._User.Entity = value; + if ((value != null)) + { + value.FavoriteSites.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.OAuthConsumer")] + public partial class OAuthConsumer : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty); + + private int _ConsumerId; + + private string _ConsumerKey; + + private string _ConsumerSecret; + + private string _Callback; + + private DotNetOpenAuth.OAuth.VerificationCodeFormat _VerificationCodeFormat; + + private int _VerificationCodeLength; + + private EntitySet<OAuthToken> _OAuthTokens; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnConsumerIdChanging(int value); + partial void OnConsumerIdChanged(); + partial void OnConsumerKeyChanging(string value); + partial void OnConsumerKeyChanged(); + partial void OnConsumerSecretChanging(string value); + partial void OnConsumerSecretChanged(); + partial void OnCallbackChanging(string value); + partial void OnCallbackChanged(); + partial void OnVerificationCodeFormatChanging(DotNetOpenAuth.OAuth.VerificationCodeFormat value); + partial void OnVerificationCodeFormatChanged(); + partial void OnVerificationCodeLengthChanging(int value); + partial void OnVerificationCodeLengthChanged(); + #endregion + + public OAuthConsumer() + { + this._OAuthTokens = new EntitySet<OAuthToken>(new Action<OAuthToken>(this.attach_OAuthTokens), new Action<OAuthToken>(this.detach_OAuthTokens)); + OnCreated(); + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ConsumerId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + public int ConsumerId + { + get + { + return this._ConsumerId; + } + set + { + if ((this._ConsumerId != value)) + { + this.OnConsumerIdChanging(value); + this.SendPropertyChanging(); + this._ConsumerId = value; + this.SendPropertyChanged("ConsumerId"); + this.OnConsumerIdChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ConsumerKey", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string ConsumerKey + { + get + { + return this._ConsumerKey; + } + set + { + if ((this._ConsumerKey != value)) + { + this.OnConsumerKeyChanging(value); + this.SendPropertyChanging(); + this._ConsumerKey = value; + this.SendPropertyChanged("ConsumerKey"); + this.OnConsumerKeyChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ConsumerSecret", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string ConsumerSecret + { + get + { + return this._ConsumerSecret; + } + set + { + if ((this._ConsumerSecret != value)) + { + this.OnConsumerSecretChanging(value); + this.SendPropertyChanging(); + this._ConsumerSecret = value; + this.SendPropertyChanged("ConsumerSecret"); + this.OnConsumerSecretChanged(); + } + } + } + + [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="_VerificationCodeFormat")] + public DotNetOpenAuth.OAuth.VerificationCodeFormat VerificationCodeFormat + { + get + { + return this._VerificationCodeFormat; + } + set + { + if ((this._VerificationCodeFormat != value)) + { + this.OnVerificationCodeFormatChanging(value); + this.SendPropertyChanging(); + this._VerificationCodeFormat = value; + this.SendPropertyChanged("VerificationCodeFormat"); + this.OnVerificationCodeFormatChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_VerificationCodeLength")] + public int VerificationCodeLength + { + get + { + return this._VerificationCodeLength; + } + set + { + if ((this._VerificationCodeLength != value)) + { + this.OnVerificationCodeLengthChanging(value); + this.SendPropertyChanging(); + this._VerificationCodeLength = value; + this.SendPropertyChanged("VerificationCodeLength"); + this.OnVerificationCodeLengthChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="OAuthConsumer_OAuthToken", Storage="_OAuthTokens", ThisKey="ConsumerId", OtherKey="ConsumerId")] + public EntitySet<OAuthToken> OAuthTokens + { + 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(OAuthToken entity) + { + this.SendPropertyChanging(); + entity.OAuthConsumer = this; + } + + private void detach_OAuthTokens(OAuthToken entity) + { + this.SendPropertyChanging(); + entity.OAuthConsumer = null; + } + } + + [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.OAuthToken")] + public partial class OAuthToken : INotifyPropertyChanging, INotifyPropertyChanged + { + + private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty); + + private int _TokenId; + + private string _Token; + + private string _TokenSecret; + + private OAuthServiceProvider.Code.TokenAuthorizationState _State; + + private System.DateTime _IssueDate; + + private int _ConsumerId; + + private System.Nullable<int> _UserId; + + private string _Scope; + + private string _RequestTokenVerifier; + + private string _RequestTokenCallback; + + private string _ConsumerVersion; + + private EntityRef<OAuthConsumer> _OAuthConsumer; + + private EntityRef<User> _User; + + #region Extensibility Method Definitions + partial void OnLoaded(); + partial void OnValidate(System.Data.Linq.ChangeAction action); + partial void OnCreated(); + partial void OnTokenIdChanging(int value); + partial void OnTokenIdChanged(); + partial void OnTokenChanging(string value); + partial void OnTokenChanged(); + partial void OnTokenSecretChanging(string value); + partial void OnTokenSecretChanged(); + partial void OnStateChanging(OAuthServiceProvider.Code.TokenAuthorizationState value); + partial void OnStateChanged(); + partial void OnIssueDateChanging(System.DateTime value); + partial void OnIssueDateChanged(); + partial void OnConsumerIdChanging(int value); + partial void OnConsumerIdChanged(); + partial void OnUserIdChanging(System.Nullable<int> value); + partial void OnUserIdChanged(); + partial void OnScopeChanging(string value); + partial void OnScopeChanged(); + partial void OnRequestTokenVerifierChanging(string value); + partial void OnRequestTokenVerifierChanged(); + partial void OnRequestTokenCallbackChanging(string value); + partial void OnRequestTokenCallbackChanged(); + partial void OnConsumerVersionChanging(string value); + partial void OnConsumerVersionChanged(); + #endregion + + public OAuthToken() + { + this._OAuthConsumer = default(EntityRef<OAuthConsumer>); + this._User = default(EntityRef<User>); + OnCreated(); + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TokenId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + public int TokenId + { + get + { + return this._TokenId; + } + set + { + if ((this._TokenId != value)) + { + this.OnTokenIdChanging(value); + this.SendPropertyChanging(); + this._TokenId = value; + this.SendPropertyChanged("TokenId"); + this.OnTokenIdChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Token", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string Token + { + get + { + return this._Token; + } + set + { + if ((this._Token != value)) + { + this.OnTokenChanging(value); + this.SendPropertyChanging(); + this._Token = value; + this.SendPropertyChanged("Token"); + this.OnTokenChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TokenSecret", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + public string TokenSecret + { + get + { + return this._TokenSecret; + } + set + { + if ((this._TokenSecret != value)) + { + this.OnTokenSecretChanging(value); + this.SendPropertyChanging(); + this._TokenSecret = value; + this.SendPropertyChanged("TokenSecret"); + this.OnTokenSecretChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_State", DbType="INT NOT NULL", CanBeNull=false)] + public OAuthServiceProvider.Code.TokenAuthorizationState State + { + get + { + return this._State; + } + set + { + if ((this._State != value)) + { + this.OnStateChanging(value); + this.SendPropertyChanging(); + this._State = value; + this.SendPropertyChanged("State"); + this.OnStateChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_IssueDate", DbType="DateTime NOT NULL")] + public System.DateTime IssueDate + { + get + { + return this._IssueDate; + } + set + { + if ((this._IssueDate != value)) + { + this.OnIssueDateChanging(value); + this.SendPropertyChanging(); + this._IssueDate = value; + this.SendPropertyChanged("IssueDate"); + this.OnIssueDateChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ConsumerId", DbType="Int NOT NULL")] + public int ConsumerId + { + get + { + return this._ConsumerId; + } + set + { + if ((this._ConsumerId != value)) + { + if (this._OAuthConsumer.HasLoadedOrAssignedValue) + { + throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException(); + } + this.OnConsumerIdChanging(value); + this.SendPropertyChanging(); + this._ConsumerId = value; + this.SendPropertyChanged("ConsumerId"); + this.OnConsumerIdChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="Int")] + public System.Nullable<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="_RequestTokenVerifier")] + public string RequestTokenVerifier + { + get + { + return this._RequestTokenVerifier; + } + set + { + if ((this._RequestTokenVerifier != value)) + { + this.OnRequestTokenVerifierChanging(value); + this.SendPropertyChanging(); + this._RequestTokenVerifier = value; + this.SendPropertyChanged("RequestTokenVerifier"); + this.OnRequestTokenVerifierChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_RequestTokenCallback")] + public string RequestTokenCallback + { + get + { + return this._RequestTokenCallback; + } + set + { + if ((this._RequestTokenCallback != value)) + { + this.OnRequestTokenCallbackChanging(value); + this.SendPropertyChanging(); + this._RequestTokenCallback = value; + this.SendPropertyChanged("RequestTokenCallback"); + this.OnRequestTokenCallbackChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ConsumerVersion")] + public string ConsumerVersion + { + get + { + return this._ConsumerVersion; + } + set + { + if ((this._ConsumerVersion != value)) + { + this.OnConsumerVersionChanging(value); + this.SendPropertyChanging(); + this._ConsumerVersion = value; + this.SendPropertyChanged("ConsumerVersion"); + this.OnConsumerVersionChanged(); + } + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="OAuthConsumer_OAuthToken", Storage="_OAuthConsumer", ThisKey="ConsumerId", OtherKey="ConsumerId", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")] + public OAuthConsumer OAuthConsumer + { + get + { + return this._OAuthConsumer.Entity; + } + set + { + OAuthConsumer previousValue = this._OAuthConsumer.Entity; + if (((previousValue != value) + || (this._OAuthConsumer.HasLoadedOrAssignedValue == false))) + { + this.SendPropertyChanging(); + if ((previousValue != null)) + { + this._OAuthConsumer.Entity = null; + previousValue.OAuthTokens.Remove(this); + } + this._OAuthConsumer.Entity = value; + if ((value != null)) + { + value.OAuthTokens.Add(this); + this._ConsumerId = value.ConsumerId; + } + else + { + this._ConsumerId = default(int); + } + this.SendPropertyChanged("OAuthConsumer"); + } + } + } + + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="User_OAuthToken", 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.OAuthTokens.Remove(this); + } + this._User.Entity = value; + if ((value != null)) + { + value.OAuthTokens.Add(this); + this._UserId = value.UserId; + } + else + { + this._UserId = default(Nullable<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="")] + 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)); + } + } + } +} +#pragma warning restore 1591 diff --git a/src/OAuth/OAuthServiceProvider/Code/DatabaseNonceStore.cs b/src/OAuth/OAuthServiceProvider/Code/DatabaseNonceStore.cs new file mode 100644 index 0000000..1f8f56e --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/DatabaseNonceStore.cs @@ -0,0 +1,55 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using DotNetOpenAuth.Messaging.Bindings; + + /// <summary> + /// A database-persisted nonce store. + /// </summary> + public class DatabaseNonceStore : INonceStore { + /// <summary> + /// Initializes a new instance of the <see cref="DatabaseNonceStore"/> class. + /// </summary> + public DatabaseNonceStore() { + } + + #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) { + Global.DataContext.Nonces.InsertOnSubmit(new Nonce { Context = context, Code = nonce, Timestamp = timestampUtc }); + try { + Global.DataContext.SubmitChanges(); + return true; + } catch (System.Data.Linq.DuplicateKeyException) { + return false; + } + } + + #endregion + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/DatabaseTokenManager.cs b/src/OAuth/OAuthServiceProvider/Code/DatabaseTokenManager.cs new file mode 100644 index 0000000..49da45d --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/DatabaseTokenManager.cs @@ -0,0 +1,163 @@ +//----------------------------------------------------------------------- +// <copyright file="DatabaseTokenManager.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using DotNetOpenAuth.OAuth.ChannelElements; + using DotNetOpenAuth.OAuth.Messages; + + public class DatabaseTokenManager : IServiceProviderTokenManager { + #region IServiceProviderTokenManager + + public IConsumerDescription GetConsumer(string consumerKey) { + var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault( + consumerCandidate => consumerCandidate.ConsumerKey == consumerKey); + if (consumerRow == null) { + throw new KeyNotFoundException(); + } + + return consumerRow; + } + + public IServiceProviderRequestToken GetRequestToken(string token) { + try { + return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State != TokenAuthorizationState.AccessToken); + } catch (InvalidOperationException ex) { + throw new KeyNotFoundException("Unrecognized token", ex); + } + } + + public IServiceProviderAccessToken GetAccessToken(string token) { + try { + return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State == TokenAuthorizationState.AccessToken); + } catch (InvalidOperationException ex) { + throw new KeyNotFoundException("Unrecognized token", ex); + } + } + + public void UpdateToken(IServiceProviderRequestToken token) { + // Nothing to do here, since we're using Linq To SQL, and + // We call LinqToSql's SubmitChanges method via our Global.Application_EndRequest method. + // This is a good pattern because we only save changes if the request didn't end up somehow failing. + // But if you DO want to save changes at this point, you could do it like so: + ////Global.DataContext.SubmitChanges(); + } + + #endregion + + #region ITokenManager Members + + public string GetTokenSecret(string token) { + var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault( + tokenCandidate => tokenCandidate.Token == token); + if (tokenRow == null) { + throw new ArgumentException(); + } + + return tokenRow.TokenSecret; + } + + public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) { + RequestScopedTokenMessage scopedRequest = (RequestScopedTokenMessage)request; + var consumer = Global.DataContext.OAuthConsumers.Single(consumerRow => consumerRow.ConsumerKey == request.ConsumerKey); + string scope = scopedRequest.Scope; + OAuthToken newToken = new OAuthToken { + OAuthConsumer = consumer, + Token = response.Token, + TokenSecret = response.TokenSecret, + IssueDate = DateTime.UtcNow, + Scope = scope, + }; + + Global.DataContext.OAuthTokens.InsertOnSubmit(newToken); + Global.DataContext.SubmitChanges(); + } + + /// <summary> + /// Checks whether a given request token has already been authorized + /// by some user for use by the Consumer that requested it. + /// </summary> + /// <param name="requestToken">The Consumer's request token.</param> + /// <returns> + /// True if the request token has already been fully authorized by the user + /// who owns the relevant protected resources. False if the token has not yet + /// been authorized, has expired or does not exist. + /// </returns> + public bool IsRequestTokenAuthorized(string requestToken) { + var tokenFound = Global.DataContext.OAuthTokens.SingleOrDefault( + token => token.Token == requestToken && + token.State == TokenAuthorizationState.AuthorizedRequestToken); + return tokenFound != null; + } + + public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) { + var data = Global.DataContext; + var consumerRow = data.OAuthConsumers.Single(consumer => consumer.ConsumerKey == consumerKey); + var tokenRow = data.OAuthTokens.Single(token => token.Token == requestToken && token.OAuthConsumer == consumerRow); + Debug.Assert(tokenRow.State == TokenAuthorizationState.AuthorizedRequestToken, "The token should be authorized already!"); + + // Update the existing row to be an access token. + tokenRow.IssueDate = DateTime.UtcNow; + tokenRow.State = TokenAuthorizationState.AccessToken; + tokenRow.Token = accessToken; + tokenRow.TokenSecret = accessTokenSecret; + } + + /// <summary> + /// Classifies a token as a request token or an access token. + /// </summary> + /// <param name="token">The token to classify.</param> + /// <returns>Request or Access token, or invalid if the token is not recognized.</returns> + public TokenType GetTokenType(string token) { + var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(tokenCandidate => tokenCandidate.Token == token); + if (tokenRow == null) { + return TokenType.InvalidToken; + } else if (tokenRow.State == TokenAuthorizationState.AccessToken) { + return TokenType.AccessToken; + } else { + return TokenType.RequestToken; + } + } + + #endregion + + public void AuthorizeRequestToken(string requestToken, User user) { + if (requestToken == null) { + throw new ArgumentNullException("requestToken"); + } + if (user == null) { + throw new ArgumentNullException("user"); + } + + var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault( + tokenCandidate => tokenCandidate.Token == requestToken && + tokenCandidate.State == TokenAuthorizationState.UnauthorizedRequestToken); + if (tokenRow == null) { + throw new ArgumentException(); + } + + tokenRow.State = TokenAuthorizationState.AuthorizedRequestToken; + tokenRow.User = user; + } + + public OAuthConsumer GetConsumerForToken(string token) { + if (string.IsNullOrEmpty(token)) { + throw new ArgumentNullException("requestToken"); + } + + var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault( + tokenCandidate => tokenCandidate.Token == token); + if (tokenRow == null) { + throw new ArgumentException(); + } + + return tokenRow.OAuthConsumer; + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/Global.cs b/src/OAuth/OAuthServiceProvider/Code/Global.cs new file mode 100644 index 0000000..60fed9f --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/Global.cs @@ -0,0 +1,135 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Linq; + using System.ServiceModel; + using System.Text; + using System.Web; + using DotNetOpenAuth.OAuth.Messages; + + /// <summary> + /// The web application global events and properties. + /// </summary> + public class Global : HttpApplication { + /// <summary> + /// An application memory cache of recent log messages. + /// </summary> + public static StringBuilder LogMessages = new StringBuilder(); + + /// <summary> + /// The logger for this sample to use. + /// </summary> + public static log4net.ILog Logger = log4net.LogManager.GetLogger("DotNetOpenAuth.OAuthServiceProvider"); + + /// <summary> + /// Gets the transaction-protected database connection for the current request. + /// </summary> + public static DataClassesDataContext DataContext { + get { + DataClassesDataContext dataContext = dataContextSimple; + if (dataContext == null) { + dataContext = new DataClassesDataContext(); + dataContext.Connection.Open(); + dataContext.Transaction = dataContext.Connection.BeginTransaction(); + dataContextSimple = dataContext; + } + + return dataContext; + } + } + + public static DatabaseTokenManager TokenManager { get; set; } + + public static DatabaseNonceStore NonceStore { get; set; } + + public static User LoggedInUser { + get { return Global.DataContext.Users.SingleOrDefault(user => user.OpenIDClaimedIdentifier == HttpContext.Current.User.Identity.Name); } + } + + public static UserAuthorizationRequest PendingOAuthAuthorization { + get { return HttpContext.Current.Session["authrequest"] as UserAuthorizationRequest; } + set { HttpContext.Current.Session["authrequest"] = value; } + } + + private static DataClassesDataContext dataContextSimple { + get { + if (HttpContext.Current != null) { + return HttpContext.Current.Items["DataContext"] as DataClassesDataContext; + } else if (OperationContext.Current != null) { + object data; + if (OperationContext.Current.IncomingMessageProperties.TryGetValue("DataContext", out data)) { + return data as DataClassesDataContext; + } else { + return null; + } + } else { + throw new InvalidOperationException(); + } + } + + set { + if (HttpContext.Current != null) { + HttpContext.Current.Items["DataContext"] = value; + } else if (OperationContext.Current != null) { + OperationContext.Current.IncomingMessageProperties["DataContext"] = value; + } else { + throw new InvalidOperationException(); + } + } + } + + public static void AuthorizePendingRequestToken() { + ITokenContainingMessage tokenMessage = PendingOAuthAuthorization; + TokenManager.AuthorizeRequestToken(tokenMessage.Token, LoggedInUser); + PendingOAuthAuthorization = null; + } + + private static void CommitAndCloseDatabaseIfNecessary() { + var dataContext = dataContextSimple; + if (dataContext != null) { + dataContext.SubmitChanges(); + dataContext.Transaction.Commit(); + dataContext.Connection.Close(); + } + } + + private void Application_Start(object sender, EventArgs e) { + log4net.Config.XmlConfigurator.Configure(); + Logger.Info("Sample starting..."); + string appPath = HttpContext.Current.Request.ApplicationPath; + if (!appPath.EndsWith("/")) { + appPath += "/"; + } + + // This will break in IIS Integrated Pipeline mode, since applications + // start before the first incoming request context is available. + // TODO: fix this. + Constants.WebRootUrl = new Uri(HttpContext.Current.Request.Url, appPath); + Global.TokenManager = new DatabaseTokenManager(); + Global.NonceStore = new DatabaseNonceStore(); + } + + private void Application_End(object sender, EventArgs e) { + Logger.Info("Sample shutting down..."); + + // this would be automatic, but in partial trust scenarios it is not. + log4net.LogManager.Shutdown(); + } + + private void Application_Error(object sender, EventArgs e) { + Logger.Error("An unhandled exception occurred in ASP.NET processing: " + Server.GetLastError(), Server.GetLastError()); + + // In the event of an unhandled exception, reverse any changes that were made to the database to avoid any partial database updates. + var dataContext = dataContextSimple; + if (dataContext != null) { + dataContext.Transaction.Rollback(); + dataContext.Connection.Close(); + dataContext.Dispose(); + dataContextSimple = null; + } + } + + private void Application_EndRequest(object sender, EventArgs e) { + CommitAndCloseDatabaseIfNecessary(); + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/IDataApi.cs b/src/OAuth/OAuthServiceProvider/Code/IDataApi.cs new file mode 100644 index 0000000..45853cd --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/IDataApi.cs @@ -0,0 +1,20 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Runtime.Serialization; + using System.ServiceModel; + using System.Text; + + [ServiceContract] + public interface IDataApi { + [OperationContract] + int? GetAge(); + + [OperationContract] + string GetName(); + + [OperationContract] + string[] GetFavoriteSites(); + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs b/src/OAuth/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs new file mode 100644 index 0000000..917a252 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs @@ -0,0 +1,65 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.IdentityModel.Policy; + using System.Linq; + using System.Security.Principal; + using System.ServiceModel; + using System.ServiceModel.Channels; + using System.ServiceModel.Security; + using DotNetOpenAuth; + using DotNetOpenAuth.OAuth; + + /// <summary> + /// A WCF extension to authenticate incoming messages using OAuth. + /// </summary> + public class OAuthAuthorizationManager : ServiceAuthorizationManager { + public OAuthAuthorizationManager() { + } + + protected override bool CheckAccessCore(OperationContext operationContext) { + if (!base.CheckAccessCore(operationContext)) { + return false; + } + + HttpRequestMessageProperty httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; + Uri requestUri = operationContext.RequestContext.RequestMessage.Properties.Via; + ServiceProvider sp = Constants.CreateServiceProvider(); + try { + var auth = sp.ReadProtectedResourceAuthorization(httpDetails, requestUri); + if (auth != null) { + var accessToken = Global.DataContext.OAuthTokens.Single(token => token.Token == auth.AccessToken); + + var principal = sp.CreatePrincipal(auth); + var policy = new OAuthPrincipalAuthorizationPolicy(principal); + var policies = new List<IAuthorizationPolicy> { + policy, + }; + + var securityContext = new ServiceSecurityContext(policies.AsReadOnly()); + if (operationContext.IncomingMessageProperties.Security != null) { + operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext; + } else { + operationContext.IncomingMessageProperties.Security = new SecurityMessageProperty { + ServiceSecurityContext = securityContext, + }; + } + + securityContext.AuthorizationContext.Properties["Identities"] = new List<IIdentity> { + principal.Identity, + }; + + // Only allow this method call if the access token scope permits it. + string[] scopes = accessToken.Scope.Split('|'); + if (scopes.Contains(operationContext.IncomingMessageHeaders.Action)) { + return true; + } + } + } catch (ProtocolException ex) { + Global.Logger.Error("Error processing OAuth messages.", ex); + } + + return false; + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/OAuthConsumer.cs b/src/OAuth/OAuthServiceProvider/Code/OAuthConsumer.cs new file mode 100644 index 0000000..341afd4 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/OAuthConsumer.cs @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuthConsumer.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using DotNetOpenAuth.OAuth.ChannelElements; + + public partial class OAuthConsumer : IConsumerDescription { + #region IConsumerDescription Members + + string IConsumerDescription.Key { + get { return this.ConsumerKey; } + } + + string IConsumerDescription.Secret { + get { return this.ConsumerSecret; } + } + + System.Security.Cryptography.X509Certificates.X509Certificate2 IConsumerDescription.Certificate { + get { return null; } + } + + Uri IConsumerDescription.Callback { + get { return string.IsNullOrEmpty(this.Callback) ? null : new Uri(this.Callback); } + } + + DotNetOpenAuth.OAuth.VerificationCodeFormat IConsumerDescription.VerificationCodeFormat { + get { return this.VerificationCodeFormat; } + } + + int IConsumerDescription.VerificationCodeLength { + get { return this.VerificationCodeLength; } + } + + #endregion + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs b/src/OAuth/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs new file mode 100644 index 0000000..a25f4c5 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs @@ -0,0 +1,47 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.IdentityModel.Claims; + using System.IdentityModel.Policy; + using System.Linq; + using System.Web; + using DotNetOpenAuth.OAuth.ChannelElements; + + public class OAuthPrincipalAuthorizationPolicy : IAuthorizationPolicy { + private readonly Guid uniqueId = Guid.NewGuid(); + private readonly OAuthPrincipal principal; + + /// <summary> + /// Initializes a new instance of the <see cref="OAuthPrincipalAuthorizationPolicy"/> class. + /// </summary> + /// <param name="principal">The principal.</param> + public OAuthPrincipalAuthorizationPolicy(OAuthPrincipal principal) { + this.principal = principal; + } + + #region IAuthorizationComponent Members + + /// <summary> + /// Gets a unique ID for this instance. + /// </summary> + public string Id { + get { return this.uniqueId.ToString(); } + } + + #endregion + + #region IAuthorizationPolicy Members + + public ClaimSet Issuer { + get { return ClaimSet.System; } + } + + public bool Evaluate(EvaluationContext evaluationContext, ref object state) { + evaluationContext.AddClaimSet(this, new DefaultClaimSet(Claim.CreateNameClaim(this.principal.Identity.Name))); + evaluationContext.Properties["Principal"] = this.principal; + return true; + } + + #endregion + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/OAuthToken.cs b/src/OAuth/OAuthServiceProvider/Code/OAuthToken.cs new file mode 100644 index 0000000..709b139 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/OAuthToken.cs @@ -0,0 +1,95 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuthToken.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using DotNetOpenAuth.OAuth.ChannelElements; + + public partial class OAuthToken : IServiceProviderRequestToken, IServiceProviderAccessToken { + #region IServiceProviderRequestToken Members + + string IServiceProviderRequestToken.Token { + get { return this.Token; } + } + + string IServiceProviderRequestToken.ConsumerKey { + get { return this.OAuthConsumer.ConsumerKey; } + } + + DateTime IServiceProviderRequestToken.CreatedOn { + get { return this.IssueDate; } + } + + Uri IServiceProviderRequestToken.Callback { + get { return string.IsNullOrEmpty(this.RequestTokenCallback) ? null : new Uri(this.RequestTokenCallback); } + set { this.RequestTokenCallback = value.AbsoluteUri; } + } + + string IServiceProviderRequestToken.VerificationCode { + get { return this.RequestTokenVerifier; } + set { this.RequestTokenVerifier = value; } + } + + Version IServiceProviderRequestToken.ConsumerVersion { + get { return new Version(this.ConsumerVersion); } + set { this.ConsumerVersion = value.ToString(); } + } + + #endregion + + #region IServiceProviderAccessToken Members + + string IServiceProviderAccessToken.Token { + get { return this.Token; } + } + + DateTime? IServiceProviderAccessToken.ExpirationDate { + get { return null; } + } + + string IServiceProviderAccessToken.Username { + get { return this.User.OpenIDClaimedIdentifier; } + } + + string[] IServiceProviderAccessToken.Roles { + get { return this.Scope.Split('|'); } + } + + #endregion + + /// <summary> + /// Called by LinqToSql when the <see cref="IssueDate"/> property is about to change. + /// </summary> + /// <param name="value">The value.</param> + partial void OnIssueDateChanging(DateTime value) { + if (value.Kind == DateTimeKind.Unspecified) { + throw new ArgumentException("The DateTime.Kind cannot be Unspecified to ensure accurate timestamp checks."); + } + } + + /// <summary> + /// Called by LinqToSql when <see cref="IssueDate"/> has changed. + /// </summary> + partial void OnIssueDateChanged() { + if (this.IssueDate.Kind == DateTimeKind.Local) { + this._IssueDate = this.IssueDate.ToUniversalTime(); + } + } + + /// <summary> + /// Called by LinqToSql when a token instance is deserialized. + /// </summary> + partial void OnLoaded() { + if (this.IssueDate.Kind == DateTimeKind.Unspecified) { + // this detail gets lost in db storage, but must be reaffirmed so that expiratoin checks succeed. + this._IssueDate = DateTime.SpecifyKind(this.IssueDate, DateTimeKind.Utc); + } + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/RequestScopedTokenMessage.cs b/src/OAuth/OAuthServiceProvider/Code/RequestScopedTokenMessage.cs new file mode 100644 index 0000000..984d683 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/RequestScopedTokenMessage.cs @@ -0,0 +1,25 @@ +namespace OAuthServiceProvider.Code { + using System; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth.Messages; + + /// <summary> + /// A custom web app version of the message sent to request an unauthorized token. + /// </summary> + public class RequestScopedTokenMessage : UnauthorizedTokenRequest { + /// <summary> + /// Initializes a new instance of the <see cref="RequestScopedTokenMessage"/> class. + /// </summary> + /// <param name="endpoint">The endpoint that will receive the message.</param> + /// <param name="version">The OAuth version.</param> + public RequestScopedTokenMessage(MessageReceivingEndpoint endpoint, Version version) + : base(endpoint, version) { + } + + /// <summary> + /// Gets or sets the scope of the access being requested. + /// </summary> + [MessagePart("scope", IsRequired = true)] + public string Scope { get; set; } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/TokenAuthorizationState.cs b/src/OAuth/OAuthServiceProvider/Code/TokenAuthorizationState.cs new file mode 100644 index 0000000..a9cfa4e --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/TokenAuthorizationState.cs @@ -0,0 +1,26 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + + /// <summary> + /// Various states an OAuth token can be in. + /// </summary> + public enum TokenAuthorizationState : int { + /// <summary> + /// An unauthorized request token. + /// </summary> + UnauthorizedRequestToken = 0, + + /// <summary> + /// An authorized request token. + /// </summary> + AuthorizedRequestToken = 1, + + /// <summary> + /// An authorized access token. + /// </summary> + AccessToken = 2, + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/TracePageAppender.cs b/src/OAuth/OAuthServiceProvider/Code/TracePageAppender.cs new file mode 100644 index 0000000..8f97c89 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/TracePageAppender.cs @@ -0,0 +1,13 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.IO; + using System.Web; + + public class TracePageAppender : log4net.Appender.AppenderSkeleton { + protected override void Append(log4net.Core.LoggingEvent loggingEvent) { + StringWriter sw = new StringWriter(Global.LogMessages); + Layout.Format(sw, loggingEvent); + } + } +}
\ No newline at end of file diff --git a/src/OAuth/OAuthServiceProvider/Code/Utilities.cs b/src/OAuth/OAuthServiceProvider/Code/Utilities.cs new file mode 100644 index 0000000..a225650 --- /dev/null +++ b/src/OAuth/OAuthServiceProvider/Code/Utilities.cs @@ -0,0 +1,28 @@ +namespace OAuthServiceProvider.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Principal; + using System.Web; + + /// <summary> + /// Extension methods and other helpful utility methods. + /// </summary> + public static class Utilities { + /// <summary> + /// Gets the database entity representing the user identified by a given <see cref="IIdentity"/> instance. + /// </summary> + /// <param name="identity">The identity of the user.</param> + /// <returns> + /// The database object for that user; or <c>null</c> if the user could not + /// be found or if <paramref name="identity"/> is <c>null</c> or represents an anonymous identity. + /// </returns> + public static User GetUser(this IIdentity identity) { + if (identity == null || !identity.IsAuthenticated) { + return null; + } + + return Global.DataContext.Users.SingleOrDefault(user => user.OpenIDClaimedIdentifier == identity.Name); + } + } +}
\ No newline at end of file |