diff options
Diffstat (limited to 'samples/OAuthServiceProvider')
30 files changed, 1858 insertions, 0 deletions
diff --git a/samples/OAuthServiceProvider/App_Code/Constants.cs b/samples/OAuthServiceProvider/App_Code/Constants.cs new file mode 100644 index 0000000..7780e96 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/Constants.cs @@ -0,0 +1,30 @@ +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); + } +} diff --git a/samples/OAuthServiceProvider/App_Code/CustomOAuthTypeProvider.cs b/samples/OAuthServiceProvider/App_Code/CustomOAuthTypeProvider.cs new file mode 100644 index 0000000..a4397c1 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/CustomOAuthTypeProvider.cs @@ -0,0 +1,31 @@ +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(ITokenManager 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); + } + + return message; + } +} diff --git a/samples/OAuthServiceProvider/App_Code/DataApi.cs b/samples/OAuthServiceProvider/App_Code/DataApi.cs new file mode 100644 index 0000000..a765159 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/DataApi.cs @@ -0,0 +1,20 @@ +using System.Linq; +using System.ServiceModel; + +public class DataApi : IDataApi { + private static OAuthToken AccessToken { + get { return OperationContext.Current.IncomingMessageProperties["OAuthAccessToken"] as OAuthToken; } + } + + public int? GetAge() { + return AccessToken.User.Age; + } + + public string GetName() { + return AccessToken.User.FullName; + } + + public string[] GetFavoriteSites() { + return AccessToken.User.FavoriteSites.Select(site => site.SiteUrl).ToArray(); + } +} diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml new file mode 100644 index 0000000..0b54d0d --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<Database Name="Database" 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" /> + <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="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" /> + <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> +</Database>
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout new file mode 100644 index 0000000..1fc61cf --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/DataClasses.dbml.layout @@ -0,0 +1,51 @@ +<?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.3862939453124998"> + <DataClassMoniker Name="/DataClassesDataContext/OAuthConsumer" /> + <nestedChildShapes> + <elementListCompartment Id="464308c4-d112-4448-b0c9-d9b82fb0ca4e" absoluteBounds="0.64, 3.71, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <classShape Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" absoluteBounds="3.5, 3.125, 2, 2.3478011067708326"> + <DataClassMoniker Name="/DataClassesDataContext/OAuthToken" /> + <nestedChildShapes> + <elementListCompartment Id="403126d0-3d2a-4af4-b0b8-c489a830bbd4" absoluteBounds="3.515, 3.585, 1.9700000000000002, 1.7878011067708333" 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 : 3.94314697265625); (3.5 : 3.94314697265625)]" fixedFrom="Algorithm" fixedTo="Algorithm"> + <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.08579752604167); (3.5 : 5.08579752604167)]" fixedFrom="Algorithm" fixedTo="Algorithm"> + <AssociationMoniker Name="/DataClassesDataContext/User/User_OAuthToken" /> + <nodes> + <classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" /> + <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> + </nodes> + </associationConnector> + </nestedChildShapes> +</ordesignerObjectsDiagram>
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs b/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs new file mode 100644 index 0000000..2fc532e --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/DataClasses.designer.cs @@ -0,0 +1,923 @@ +#pragma warning disable 1591 +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.3053 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Data.Linq; +using System.Data.Linq.Mapping; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + + + +[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); + #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>(); + } + } +} + +[Table(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(); + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Association(Name="User_FavoriteSite", Storage="_FavoriteSites", ThisKey="UserId", OtherKey="UserId")] + public EntitySet<FavoriteSite> FavoriteSites + { + get + { + return this._FavoriteSites; + } + set + { + this._FavoriteSites.Assign(value); + } + } + + [Association(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; + } +} + +[Table(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(); + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Association(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)); + } + } +} + +[Table(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 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(); + #endregion + + public OAuthConsumer() + { + this._OAuthTokens = new EntitySet<OAuthToken>(new Action<OAuthToken>(this.attach_OAuthTokens), new Action<OAuthToken>(this.detach_OAuthTokens)); + OnCreated(); + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Association(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; + } +} + +[Table(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 TokenAuthorizationState _State; + + private System.DateTime _IssueDate; + + private int _ConsumerId; + + private System.Nullable<int> _UserId; + + private string _Scope; + + 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(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(); + #endregion + + public OAuthToken() + { + this._OAuthConsumer = default(EntityRef<OAuthConsumer>); + this._User = default(EntityRef<User>); + OnCreated(); + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(Storage="_State", DbType="Int NOT NULL", CanBeNull=false)] + public TokenAuthorizationState State + { + get + { + return this._State; + } + set + { + if ((this._State != value)) + { + this.OnStateChanging(value); + this.SendPropertyChanging(); + this._State = value; + this.SendPropertyChanged("State"); + this.OnStateChanged(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Column(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(); + } + } + } + + [Association(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"); + } + } + } + + [Association(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)); + } + } +} +#pragma warning restore 1591 diff --git a/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs b/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs new file mode 100644 index 0000000..b5d8fdd --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/DatabaseTokenManager.cs @@ -0,0 +1,118 @@ +//----------------------------------------------------------------------- +// <copyright file="DatabaseTokenManager.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using DotNetOpenAuth.OAuth.ChannelElements; +using DotNetOpenAuth.OAuth.Messages; + +public class DatabaseTokenManager : ITokenManager { + #region ITokenManager Members + + public string GetConsumerSecret(string consumerKey) { + var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault( + consumerCandidate => consumerCandidate.ConsumerKey == consumerKey); + if (consumerRow == null) { + throw new ArgumentException(); + } + + return consumerRow.ConsumerSecret; + } + + 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); + } + + /// <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; + } +} diff --git a/samples/OAuthServiceProvider/App_Code/Global.cs b/samples/OAuthServiceProvider/App_Code/Global.cs new file mode 100644 index 0000000..b343dcd --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/Global.cs @@ -0,0 +1,114 @@ +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.ConsumerSample"); + + /// <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 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..."); + Constants.WebRootUrl = new Uri(HttpContext.Current.Request.Url, "/"); + var tokenManager = new DatabaseTokenManager(); + Global.TokenManager = tokenManager; + } + + 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()); + } + + private void Application_EndRequest(object sender, EventArgs e) { + CommitAndCloseDatabaseIfNecessary(); + } +} diff --git a/samples/OAuthServiceProvider/App_Code/IDataApi.cs b/samples/OAuthServiceProvider/App_Code/IDataApi.cs new file mode 100644 index 0000000..350df35 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/IDataApi.cs @@ -0,0 +1,18 @@ +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(); +} diff --git a/samples/OAuthServiceProvider/App_Code/OAuthAuthorizationManager.cs b/samples/OAuthServiceProvider/App_Code/OAuthAuthorizationManager.cs new file mode 100644 index 0000000..fce1ad4 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/OAuthAuthorizationManager.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Channels; +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["OriginalHttpRequestUri"] as Uri; + ServiceProvider sp = Constants.CreateServiceProvider(); + var auth = sp.ReadProtectedResourceAuthorization(httpDetails, requestUri); + if (auth != null) { + var accessToken = Global.DataContext.OAuthTokens.Single(token => token.Token == auth.AccessToken); + + // Only allow this method call if the access token scope permits it. + string[] scopes = accessToken.Scope.Split('|'); + if (scopes.Contains(operationContext.IncomingMessageHeaders.Action)) { + operationContext.IncomingMessageProperties["OAuthAccessToken"] = accessToken; + return true; + } + } + + return false; + } +} diff --git a/samples/OAuthServiceProvider/App_Code/RequestScopedTokenMessage.cs b/samples/OAuthServiceProvider/App_Code/RequestScopedTokenMessage.cs new file mode 100644 index 0000000..b33a734 --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/RequestScopedTokenMessage.cs @@ -0,0 +1,20 @@ +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> + public RequestScopedTokenMessage(MessageReceivingEndpoint endpoint) : base(endpoint) { + } + + /// <summary> + /// Gets or sets the scope of the access being requested. + /// </summary> + [MessagePart("scope", IsRequired = true)] + public string Scope { get; set; } +} diff --git a/samples/OAuthServiceProvider/App_Code/TokenAuthorizationState.cs b/samples/OAuthServiceProvider/App_Code/TokenAuthorizationState.cs new file mode 100644 index 0000000..8d3c8ac --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/TokenAuthorizationState.cs @@ -0,0 +1,24 @@ +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, +} diff --git a/samples/OAuthServiceProvider/App_Code/TracePageAppender.cs b/samples/OAuthServiceProvider/App_Code/TracePageAppender.cs new file mode 100644 index 0000000..7490f3d --- /dev/null +++ b/samples/OAuthServiceProvider/App_Code/TracePageAppender.cs @@ -0,0 +1,11 @@ +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); + } +} diff --git a/samples/OAuthServiceProvider/Bin/log4net.dll.refresh b/samples/OAuthServiceProvider/Bin/log4net.dll.refresh Binary files differnew file mode 100644 index 0000000..ede40da --- /dev/null +++ b/samples/OAuthServiceProvider/Bin/log4net.dll.refresh diff --git a/samples/OAuthServiceProvider/DataApi.svc b/samples/OAuthServiceProvider/DataApi.svc new file mode 100644 index 0000000..4e9e477 --- /dev/null +++ b/samples/OAuthServiceProvider/DataApi.svc @@ -0,0 +1 @@ +<%@ ServiceHost Language="C#" Debug="true" Service="DataApi" CodeBehind="~/App_Code/DataApi.cs" %> diff --git a/samples/OAuthServiceProvider/Default.aspx b/samples/OAuthServiceProvider/Default.aspx new file mode 100644 index 0000000..67efe3a --- /dev/null +++ b/samples/OAuthServiceProvider/Default.aspx @@ -0,0 +1,50 @@ +<%@ Page Title="DotNetOpenAuth Service Provider Sample" Language="C#" MasterPageFile="~/MasterPage.master" %> + +<%@ Import Namespace="System.IO" %> +<%@ Import Namespace="System.Data.SqlClient" %> + +<script runat="server"> + + protected void createDatabaseButton_Click(object sender, EventArgs e) { + string dbPath = Path.Combine(Server.MapPath(Request.ApplicationPath), "App_Data"); + if (!Directory.Exists(dbPath)) { + Directory.CreateDirectory(dbPath); + } + string connectionString = ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString.Replace("|DataDirectory|", dbPath); + var dc = new DataClassesDataContext(connectionString); + if (dc.DatabaseExists()) { + dc.DeleteDatabase(); + } + try { + dc.CreateDatabase(); + // Fill with sample data. + dc.OAuthConsumers.InsertOnSubmit(new OAuthConsumer { + ConsumerKey = "sampleconsumer", + ConsumerSecret = "samplesecret", + }); + dc.Users.InsertOnSubmit(new User { + OpenIDFriendlyIdentifier = "=arnott", + OpenIDClaimedIdentifier = "=!9B72.7DD1.50A9.5CCD", + Age = 27, + FullName = "Andrew Arnott", + FavoriteSites = new System.Data.Linq.EntitySet<FavoriteSite> { + new FavoriteSite { SiteUrl = "http://www.microsoft.com" }, + new FavoriteSite { SiteUrl = "http://www.google.com" }, + }, + }); + + dc.SubmitChanges(); + databaseStatus.Visible = true; + } catch (System.Data.SqlClient.SqlException ex) { + foreach (System.Data.SqlClient.SqlError error in ex.Errors) { + Response.Write(error.Message); + } + } + } +</script> + +<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server"> + <asp:Button ID="createDatabaseButton" runat="server" Text="(Re)create Database" OnClick="createDatabaseButton_Click" /> + <asp:Label runat="server" ID="databaseStatus" EnableViewState="false" Text="Database recreated!" + Visible="false" /> +</asp:Content> diff --git a/samples/OAuthServiceProvider/Global.asax b/samples/OAuthServiceProvider/Global.asax new file mode 100644 index 0000000..e9ae062 --- /dev/null +++ b/samples/OAuthServiceProvider/Global.asax @@ -0,0 +1 @@ +<%@ Application Inherits="Global" CodeBehind="App_Code\Global.cs" %>
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/Login.aspx b/samples/OAuthServiceProvider/Login.aspx new file mode 100644 index 0000000..d63b2c8 --- /dev/null +++ b/samples/OAuthServiceProvider/Login.aspx @@ -0,0 +1,7 @@ +<%@ Page Title="Login" Language="C#" MasterPageFile="~/MasterPage.master" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.RelyingParty" TagPrefix="rp" %> + +<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server"> + <rp:OpenIdLogin runat="server" TabIndex='1' /> +</asp:Content> diff --git a/samples/OAuthServiceProvider/MasterPage.master b/samples/OAuthServiceProvider/MasterPage.master new file mode 100644 index 0000000..136dfc9 --- /dev/null +++ b/samples/OAuthServiceProvider/MasterPage.master @@ -0,0 +1,23 @@ +<%@ Master Language="C#" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<script runat="server"> + +</script> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title>DotNetOpenAuth Service Provider sample</title> + <asp:ContentPlaceHolder ID="head" runat="server"/> +</head> +<body> + <form id="form1" runat="server"> + <h1>DotNetOpenAuth Service Provider sample</h1> + <div> + <asp:ContentPlaceHolder ID="Body" runat="server"> + </asp:ContentPlaceHolder> + </div> + </form> +</body> +</html> diff --git a/samples/OAuthServiceProvider/Members/Authorize.aspx b/samples/OAuthServiceProvider/Members/Authorize.aspx new file mode 100644 index 0000000..0fd272c --- /dev/null +++ b/samples/OAuthServiceProvider/Members/Authorize.aspx @@ -0,0 +1,32 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" + CodeFile="Authorize.aspx.cs" Inherits="Authorize" %> + +<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server"> + <asp:MultiView runat="server" ActiveViewIndex="0" ID="multiView"> + <asp:View runat="server"> + <div style="background-color: Yellow"> + <b>Warning</b>: Never give your login credentials to another web site or application. + </div> + <p>The client web site or application + <asp:Label ID="consumerLabel" Font-Bold="true" runat="server" Text="[consumer]" /> + wants access to your + <asp:Label ID="desiredAccessLabel" Font-Bold="true" runat="server" Text="[protected resource]" />. + </p> + <p>Do you want to allow this? </p> + <div> + <asp:Button ID="allowAccessButton" runat="server" Text="Yes" OnClick="allowAccessButton_Click" /> + <asp:Button ID="denyAccessButton" runat="server" Text="No" + onclick="denyAccessButton_Click" /> + </div> + <p>If you grant access now, you can revoke it at any time by returning to this page. + </p> + </asp:View> + <asp:View runat="server"> + <p>Authorization has been granted. Please inform the consumer application or web site + of this. </p> + </asp:View> + <asp:View runat="server"> + <p>Authorization has been denied. You're free to do whatever now. </p> + </asp:View> + </asp:MultiView> +</asp:Content> diff --git a/samples/OAuthServiceProvider/Members/Authorize.aspx.cs b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs new file mode 100644 index 0000000..76eec26 --- /dev/null +++ b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using DotNetOpenAuth; +using DotNetOpenAuth.OAuth; +using DotNetOpenAuth.OAuth.Messages; + +/// <summary> +/// Conducts the user through a Consumer authorization process. +/// </summary> +public partial class Authorize : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + if (!IsPostBack) { + if (Global.PendingOAuthAuthorization == null) { + Response.Redirect("~/Members/AuthorizedConsumers.aspx"); + } else { + ITokenContainingMessage pendingToken = Global.PendingOAuthAuthorization; + var token = Global.DataContext.OAuthTokens.Single(t => t.Token == pendingToken.Token); + desiredAccessLabel.Text = token.Scope; + } + } + } + + protected void allowAccessButton_Click(object sender, EventArgs e) { + var pending = Global.PendingOAuthAuthorization; + Global.AuthorizePendingRequestToken(); + multiView.ActiveViewIndex = 1; + + ServiceProvider sp = new ServiceProvider(Constants.SelfDescription, Global.TokenManager); + var response = sp.PrepareAuthorizationResponse(pending); + if (response != null) { + sp.Channel.Send(response); + } + } + + protected void denyAccessButton_Click(object sender, EventArgs e) { + // erase the request token. + multiView.ActiveViewIndex = 2; + } +} diff --git a/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx b/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx new file mode 100644 index 0000000..d6ea668 --- /dev/null +++ b/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx @@ -0,0 +1,7 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" + CodeFile="AuthorizedConsumers.aspx.cs" Inherits="AuthorizedConsumers" %> + +<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server"> + <h2>The following consumers have access to your data</h2> + <p>TODO</p> +</asp:Content> diff --git a/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx.cs b/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx.cs new file mode 100644 index 0000000..e7af629 --- /dev/null +++ b/samples/OAuthServiceProvider/Members/AuthorizedConsumers.aspx.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +/// <summary> +/// Lists the consumers that have active request or access tokens +/// and provides a mechanism for the user to revoke permissions. +/// </summary> +public partial class AuthorizedConsumers : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + } +} diff --git a/samples/OAuthServiceProvider/Members/Logoff.aspx b/samples/OAuthServiceProvider/Members/Logoff.aspx new file mode 100644 index 0000000..afa9dd9 --- /dev/null +++ b/samples/OAuthServiceProvider/Members/Logoff.aspx @@ -0,0 +1,8 @@ +<%@ Page Title="Log off" Language="C#" MasterPageFile="~/MasterPage.master" %> + +<script runat="server"> + private void Page_Load(object sender, EventArgs e) { + FormsAuthentication.SignOut(); + Response.Redirect("~/"); + } +</script> diff --git a/samples/OAuthServiceProvider/Members/Web.config b/samples/OAuthServiceProvider/Members/Web.config new file mode 100644 index 0000000..50fab27 --- /dev/null +++ b/samples/OAuthServiceProvider/Members/Web.config @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<configuration> + <system.web> + <authorization> + <deny users="?"/> + </authorization> + </system.web> +</configuration> diff --git a/samples/OAuthServiceProvider/OAuth.ashx b/samples/OAuthServiceProvider/OAuth.ashx new file mode 100644 index 0000000..46a516f --- /dev/null +++ b/samples/OAuthServiceProvider/OAuth.ashx @@ -0,0 +1,41 @@ +<%@ WebHandler Language="C#" Class="OAuth" %> + +using System; +using System.Linq; +using System.Web; +using System.Web.SessionState; +using DotNetOpenAuth.OAuth; +using DotNetOpenAuth.OAuth.ChannelElements; +using DotNetOpenAuth.OAuth.Messages; +using DotNetOpenAuth.Messaging; + +public class OAuth : IHttpHandler, IRequiresSessionState { + ServiceProvider sp; + + public OAuth() { + sp = new ServiceProvider(Constants.SelfDescription, Global.TokenManager, new CustomOAuthMessageFactory(Global.TokenManager)); + } + + public void ProcessRequest(HttpContext context) { + IProtocolMessage request = sp.ReadRequest(); + RequestScopedTokenMessage requestToken; + UserAuthorizationRequest requestAuth; + AuthorizedTokenRequest requestAccessToken; + if ((requestToken = request as RequestScopedTokenMessage) != null) { + var response = sp.PrepareUnauthorizedTokenMessage(requestToken); + sp.Channel.Send(response); + } else if ((requestAuth = request as UserAuthorizationRequest) != null) { + Global.PendingOAuthAuthorization = requestAuth; + HttpContext.Current.Response.Redirect("~/Members/Authorize.aspx"); + } else if ((requestAccessToken = request as AuthorizedTokenRequest) != null) { + var response = sp.PrepareAccessTokenMessage(requestAccessToken); + sp.Channel.Send(response); + } else { + throw new InvalidOperationException(); + } + } + + public bool IsReusable { + get { return true; } + } +} diff --git a/samples/OAuthServiceProvider/Settings.StyleCop b/samples/OAuthServiceProvider/Settings.StyleCop new file mode 100644 index 0000000..7f55ce6 --- /dev/null +++ b/samples/OAuthServiceProvider/Settings.StyleCop @@ -0,0 +1 @@ +<StyleCopSettings Version="4.3" />
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/TracePage.aspx b/samples/OAuthServiceProvider/TracePage.aspx new file mode 100644 index 0000000..4d6ecc5 --- /dev/null +++ b/samples/OAuthServiceProvider/TracePage.aspx @@ -0,0 +1,18 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TracePage.aspx.cs" Inherits="TracePage" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <p align="right"> + <asp:Button runat="server" Text="Clear log" ID="clearLogButton" OnClick="clearLogButton_Click" /> + </p> + <pre> + <asp:PlaceHolder runat="server" ID="placeHolder1" /> + </pre> + </form> +</body> +</html> diff --git a/samples/OAuthServiceProvider/TracePage.aspx.cs b/samples/OAuthServiceProvider/TracePage.aspx.cs new file mode 100644 index 0000000..52848f2 --- /dev/null +++ b/samples/OAuthServiceProvider/TracePage.aspx.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +/// <summary> +/// A page to display recent log messages. +/// </summary> +public partial class TracePage : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + this.placeHolder1.Controls.Add(new Label { Text = HttpUtility.HtmlEncode(Global.LogMessages.ToString()) }); + } + + protected void clearLogButton_Click(object sender, EventArgs e) { + Global.LogMessages.Length = 0; + + // clear the page immediately, and allow for F5 without a Postback warning. + Response.Redirect(Request.Url.AbsoluteUri); + } +} diff --git a/samples/OAuthServiceProvider/Web.config b/samples/OAuthServiceProvider/Web.config new file mode 100644 index 0000000..f4bd208 --- /dev/null +++ b/samples/OAuthServiceProvider/Web.config @@ -0,0 +1,140 @@ +<?xml version="1.0"?> +<configuration> + <configSections> + <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false"/> + <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/> + <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + </sectionGroup> + </sectionGroup> + </sectionGroup> + </configSections> + <appSettings/> + <connectionStrings> + <add name="DatabaseConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True" + providerName="System.Data.SqlClient" /> + </connectionStrings> + <system.web> + <!-- + Set compilation debug="true" to insert debugging + symbols into the compiled page. Because this + affects performance, set this value to true only + during development. + --> + <compilation debug="true"> + <assemblies> + <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + </assemblies> + </compilation> + <authentication mode="Forms"> + <forms name="oauthSP" /> + </authentication> + <pages> + <controls> + <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </controls> + </pages> + <httpHandlers> + <remove verb="*" path="*.asmx"/> + <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/> + </httpHandlers> + <httpModules> + <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </httpModules> + </system.web> + <system.codedom> + <compilers> + <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <providerOption name="CompilerVersion" value="v3.5"/> + <providerOption name="WarnAsError" value="false"/> + </compiler> + <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <providerOption name="CompilerVersion" value="v3.5"/> + <providerOption name="OptionInfer" value="true"/> + <providerOption name="WarnAsError" value="false"/> + </compiler> + </compilers> + </system.codedom> + <!-- + The system.webServer section is required for running ASP.NET AJAX under Internet + Information Services 7.0. It is not necessary for previous version of IIS. + --> + <system.webServer> + <validation validateIntegratedModeConfiguration="false"/> + <modules> + <remove name="ScriptModule"/> + <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </modules> + <handlers> + <remove name="WebServiceHandlerFactory-Integrated"/> + <remove name="ScriptHandlerFactory"/> + <remove name="ScriptHandlerFactoryAppServices"/> + <remove name="ScriptResource"/> + <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </handlers> + </system.webServer> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + </assemblyBinding> + </runtime> + <log4net> + <appender name="TracePageAppender" type="TracePageAppender, __code"> + <layout type="log4net.Layout.PatternLayout"> + <conversionPattern value="%date (GMT%date{%z}) [%thread] %-5level %logger - %message%newline"/> + </layout> + </appender> + <!-- Setup the root category, add the appenders and set the default level --> + <root> + <level value="INFO"/> + <!--<appender-ref ref="RollingFileAppender" />--> + <appender-ref ref="TracePageAppender"/> + </root> + <!-- Specify the level for some specific categories --> + <logger name="DotNetOpenAuth"> + <level value="ALL"/> + </logger> + </log4net> + <system.serviceModel> + <behaviors> + <serviceBehaviors> + <behavior name="DataApiBehavior"> + <serviceMetadata httpGetEnabled="true"/> + <serviceDebug includeExceptionDetailInFaults="true"/> + <serviceAuthorization serviceAuthorizationManagerType="OAuthAuthorizationManager, __code"/> + </behavior> + </serviceBehaviors> + </behaviors> + <services> + <service behaviorConfiguration="DataApiBehavior" name="DataApi"> + <endpoint address="" binding="wsHttpBinding" contract="IDataApi"> + <identity> + <dns value="localhost"/> + </identity> + </endpoint> + <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> + </service> + </services> + </system.serviceModel> +</configuration> |