diff options
26 files changed, 256 insertions, 451 deletions
diff --git a/projecttemplates/RelyingPartyLogic/Model.Designer.cs b/projecttemplates/RelyingPartyLogic/Model.Designer.cs index 8884760..6f237a1 100644 --- a/projecttemplates/RelyingPartyLogic/Model.Designer.cs +++ b/projecttemplates/RelyingPartyLogic/Model.Designer.cs @@ -15,7 +15,7 @@ [assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("DatabaseModel", "FK_IssuedToken_User", "User", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(RelyingPartyLogic.User), "ClientAuthorization", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(RelyingPartyLogic.ClientAuthorization))] // Original file name: -// Generation date: 7/14/2010 9:35:17 PM +// Generation date: 7/22/2010 11:15:43 AM namespace RelyingPartyLogic { @@ -1437,32 +1437,32 @@ namespace RelyingPartyLogic [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")] partial void OnCreatedOnUtcChanged(); /// <summary> - /// There are no comments for property ExpirationDate in the schema. + /// There are no comments for property ExpirationDateUtc in the schema. /// </summary> [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")] - public global::System.Nullable<global::System.DateTime> ExpirationDate + public global::System.Nullable<global::System.DateTime> ExpirationDateUtc { get { - return this._ExpirationDate; + return this._ExpirationDateUtc; } set { - this.OnExpirationDateChanging(value); - this.ReportPropertyChanging("ExpirationDate"); - this._ExpirationDate = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); - this.ReportPropertyChanged("ExpirationDate"); - this.OnExpirationDateChanged(); + this.OnExpirationDateUtcChanging(value); + this.ReportPropertyChanging("ExpirationDateUtc"); + this._ExpirationDateUtc = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); + this.ReportPropertyChanged("ExpirationDateUtc"); + this.OnExpirationDateUtcChanged(); } } [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")] - private global::System.Nullable<global::System.DateTime> _ExpirationDate; + private global::System.Nullable<global::System.DateTime> _ExpirationDateUtc; [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")] - partial void OnExpirationDateChanging(global::System.Nullable<global::System.DateTime> value); + partial void OnExpirationDateUtcChanging(global::System.Nullable<global::System.DateTime> value); [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")] - partial void OnExpirationDateChanged(); + partial void OnExpirationDateUtcChanged(); /// <summary> /// There are no comments for property Scope in the schema. /// </summary> diff --git a/projecttemplates/RelyingPartyLogic/Model.edmx b/projecttemplates/RelyingPartyLogic/Model.edmx index a003493..fd9f0fb 100644 --- a/projecttemplates/RelyingPartyLogic/Model.edmx +++ b/projecttemplates/RelyingPartyLogic/Model.edmx @@ -293,7 +293,7 @@ </Key> <Property Type="Int32" Name="AuthorizationId" Nullable="false" a:StoreGeneratedPattern="Identity" xmlns:a="http://schemas.microsoft.com/ado/2009/02/edm/annotation" /> <Property Type="DateTime" Name="CreatedOnUtc" Nullable="false" /> - <Property Type="DateTime" Name="ExpirationDate" /> + <Property Type="DateTime" Name="ExpirationDateUtc" Nullable="true" /> <Property Type="String" Name="Scope" MaxLength="2048" FixedLength="false" Unicode="false" /> <NavigationProperty Name="Client" Relationship="DatabaseModel.FK_IssuedToken_Consumer" FromRole="ClientAuthorization" ToRole="Client" /> <NavigationProperty Name="User" Relationship="DatabaseModel.FK_IssuedToken_User" FromRole="ClientAuthorization" ToRole="User" /> @@ -386,7 +386,7 @@ <EntityTypeMapping TypeName="DatabaseModel.ClientAuthorization"> <MappingFragment StoreEntitySet="ClientAuthorization"> <ScalarProperty Name="Scope" ColumnName="Scope" /> - <ScalarProperty Name="ExpirationDate" ColumnName="ExpirationDate" /> + <ScalarProperty Name="ExpirationDateUtc" ColumnName="ExpirationDate" /> <ScalarProperty Name="CreatedOnUtc" ColumnName="CreatedOn" /> <ScalarProperty Name="AuthorizationId" ColumnName="AuthorizationId" /> </MappingFragment> diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs index 3dafa0a..91a2ac3 100644 --- a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs +++ b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs @@ -151,6 +151,7 @@ namespace RelyingPartyLogic { where auth.Client.ClientIdentifier == clientIdentifier && auth.CreatedOnUtc <= issuedUtc && + (!auth.ExpirationDateUtc.HasValue || auth.ExpirationDateUtc.Value >= DateTime.UtcNow) && auth.User.AuthenticationTokens.Any(token => token.ClaimedIdentifier == username) select auth.Scope; diff --git a/samples/OAuthConsumer/Default.aspx b/samples/OAuthConsumer/Default.aspx index f3bceb6..140f002 100644 --- a/samples/OAuthConsumer/Default.aspx +++ b/samples/OAuthConsumer/Default.aspx @@ -10,6 +10,6 @@ <li><a href="Twitter.aspx">Get your Twitter updates</a></li> <li><a href="SignInWithTwitter.aspx">Sign In With Twitter</a></li> <li><a href="Facebook.aspx">Sign in with Facebook</a></li> - <li><a href="SampleWcf.aspx">Interop with Service Provider sample using WCF w/ OAuth</a></li> + <li><a href="SampleWcf2.aspx">Interop with Service Provider sample using WCF w/ OAuth 2.0</a></li> </ul> </asp:Content> diff --git a/samples/OAuthConsumer/OAuthConsumer.csproj b/samples/OAuthConsumer/OAuthConsumer.csproj index 698de7a..a4ae9ec 100644 --- a/samples/OAuthConsumer/OAuthConsumer.csproj +++ b/samples/OAuthConsumer/OAuthConsumer.csproj @@ -63,7 +63,6 @@ <Content Include="Global.asax" /> <Content Include="GoogleAddressBook.aspx" /> <Content Include="images\Sign-in-with-Twitter-darker.png" /> - <Content Include="SampleWcf.aspx" /> <Content Include="Yammer.aspx" /> <None Include="Service References\SampleServiceProvider\DataApi.disco" /> <None Include="Service References\SampleServiceProvider\configuration91.svcinfo" /> @@ -101,13 +100,6 @@ <Compile Include="GoogleAddressBook.aspx.designer.cs"> <DependentUpon>GoogleAddressBook.aspx</DependentUpon> </Compile> - <Compile Include="SampleWcf.aspx.cs"> - <DependentUpon>SampleWcf.aspx</DependentUpon> - <SubType>ASPXCodeBehind</SubType> - </Compile> - <Compile Include="SampleWcf.aspx.designer.cs"> - <DependentUpon>SampleWcf.aspx</DependentUpon> - </Compile> <Compile Include="SampleWcf2.aspx.cs"> <DependentUpon>SampleWcf2.aspx</DependentUpon> <SubType>ASPXCodeBehind</SubType> diff --git a/samples/OAuthConsumer/SampleWcf.aspx b/samples/OAuthConsumer/SampleWcf.aspx deleted file mode 100644 index fcec089..0000000 --- a/samples/OAuthConsumer/SampleWcf.aspx +++ /dev/null @@ -1,23 +0,0 @@ -<%@ Page Title="OAuth 1.0a consumer" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" Inherits="OAuthConsumer.SampleWcf" Codebehind="SampleWcf.aspx.cs" %> - -<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server"> - <fieldset title="Authorization"> - <asp:CheckBoxList runat="server" ID="scopeList"> - <asp:ListItem Value="http://tempuri.org/IDataApi/GetName">GetName</asp:ListItem> - <asp:ListItem Value="http://tempuri.org/IDataApi/GetAge">GetAge</asp:ListItem> - <asp:ListItem Value="http://tempuri.org/IDataApi/GetFavoriteSites">GetFavoriteSites</asp:ListItem> - </asp:CheckBoxList> - <asp:Button ID="getAuthorizationButton" runat="server" Text="Get Authorization" OnClick="getAuthorizationButton_Click" /> - <asp:Label ID="authorizationLabel" runat="server" /> - </fieldset> - <br /> - <asp:Button ID="getNameButton" runat="server" Text="Get Name" OnClick="getNameButton_Click" /> - <asp:Label ID="nameLabel" runat="server" /> - <br /> - <asp:Button ID="getAgeButton" runat="server" Text="Get Age" OnClick="getAgeButton_Click" /> - <asp:Label ID="ageLabel" runat="server" /> - <br /> - <asp:Button ID="getFavoriteSites" runat="server" Text="Get Favorite Sites" - onclick="getFavoriteSites_Click" /> - <asp:Label ID="favoriteSitesLabel" runat="server" /> -</asp:Content> diff --git a/samples/OAuthConsumer/SampleWcf.aspx.cs b/samples/OAuthConsumer/SampleWcf.aspx.cs deleted file mode 100644 index 74c6e6a..0000000 --- a/samples/OAuthConsumer/SampleWcf.aspx.cs +++ /dev/null @@ -1,119 +0,0 @@ -namespace OAuthConsumer { - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Net; - using System.ServiceModel; - using System.ServiceModel.Channels; - using System.ServiceModel.Security; - using System.Web.UI.WebControls; - using DotNetOpenAuth; - using DotNetOpenAuth.ApplicationBlock; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth; - using DotNetOpenAuth.OAuth.ChannelElements; - using OAuthConsumer.SampleServiceProvider; - - /// <summary> - /// Sample consumer of our Service Provider sample's WCF service. - /// </summary> - public partial class SampleWcf : System.Web.UI.Page { - protected void Page_Load(object sender, EventArgs e) { - if (!IsPostBack) { - if (Session["WcfTokenManager"] != null) { - WebConsumer consumer = this.CreateConsumer(); - var accessTokenMessage = consumer.ProcessUserAuthorization(); - if (accessTokenMessage != null) { - Session["WcfAccessToken"] = accessTokenMessage.AccessToken; - this.authorizationLabel.Text = "Authorized! Access token: " + accessTokenMessage.AccessToken; - } - } - } - } - - protected void getAuthorizationButton_Click(object sender, EventArgs e) { - WebConsumer consumer = this.CreateConsumer(); - UriBuilder callback = new UriBuilder(Request.Url); - callback.Query = null; - string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>() - where item.Selected - select item.Value).ToArray(); - string scope = string.Join(" ", scopes); - var requestParams = new Dictionary<string, string> { - { "scope", scope }, - }; - var response = consumer.PrepareRequestUserAuthorization(callback.Uri, requestParams, null); - consumer.Channel.Send(response); - } - - protected void getNameButton_Click(object sender, EventArgs e) { - try { - this.nameLabel.Text = CallService(client => client.GetName()); - } catch (SecurityAccessDeniedException) { - this.nameLabel.Text = "Access denied!"; - } - } - - protected void getAgeButton_Click(object sender, EventArgs e) { - try { - int? age = CallService(client => client.GetAge()); - this.ageLabel.Text = age.HasValue ? age.Value.ToString(CultureInfo.CurrentCulture) : "not available"; - } catch (SecurityAccessDeniedException) { - this.ageLabel.Text = "Access denied!"; - } - } - - protected void getFavoriteSites_Click(object sender, EventArgs e) { - try { - string[] favoriteSites = CallService(client => client.GetFavoriteSites()); - this.favoriteSitesLabel.Text = string.Join(", ", favoriteSites); - } catch (SecurityAccessDeniedException) { - this.favoriteSitesLabel.Text = "Access denied!"; - } - } - - private T CallService<T>(Func<DataApiClient, T> predicate) { - DataApiClient client = new DataApiClient(); - var serviceEndpoint = new MessageReceivingEndpoint(client.Endpoint.Address.Uri, HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest); - var accessToken = Session["WcfAccessToken"] as string; - if (accessToken == null) { - throw new InvalidOperationException("No access token!"); - } - WebConsumer consumer = this.CreateConsumer(); - WebRequest httpRequest = consumer.PrepareAuthorizedRequest(serviceEndpoint, accessToken); - - var httpDetails = new HttpRequestMessageProperty(); - httpDetails.Headers[HttpRequestHeader.Authorization] = httpRequest.Headers[HttpRequestHeader.Authorization]; - using (OperationContextScope scope = new OperationContextScope(client.InnerChannel)) { - OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpDetails; - return predicate(client); - } - } - - private WebConsumer CreateConsumer() { - string consumerKey = "sampleconsumer"; - string consumerSecret = "samplesecret"; - var tokenManager = Session["WcfTokenManager"] as InMemoryTokenManager; - if (tokenManager == null) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Session["WcfTokenManager"] = tokenManager; - } - MessageReceivingEndpoint oauthEndpoint = new MessageReceivingEndpoint( - new Uri("http://localhost:65169/OAuth.ashx"), - HttpDeliveryMethods.PostRequest); - WebConsumer consumer = new WebConsumer( - new ServiceProviderDescription { - RequestTokenEndpoint = oauthEndpoint, - UserAuthorizationEndpoint = oauthEndpoint, - AccessTokenEndpoint = oauthEndpoint, - TamperProtectionElements = new DotNetOpenAuth.Messaging.ITamperProtectionChannelBindingElement[] { - new HmacSha1SigningBindingElement(), - }, - }, - tokenManager); - - return consumer; - } - } -}
\ No newline at end of file diff --git a/samples/OAuthConsumer/SampleWcf.aspx.designer.cs b/samples/OAuthConsumer/SampleWcf.aspx.designer.cs deleted file mode 100644 index c041338..0000000 --- a/samples/OAuthConsumer/SampleWcf.aspx.designer.cs +++ /dev/null @@ -1,96 +0,0 @@ -//------------------------------------------------------------------------------ -// <auto-generated> -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// </auto-generated> -//------------------------------------------------------------------------------ - -namespace OAuthConsumer { - - - public partial class SampleWcf { - - /// <summary> - /// scopeList control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.CheckBoxList scopeList; - - /// <summary> - /// getAuthorizationButton control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Button getAuthorizationButton; - - /// <summary> - /// authorizationLabel control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Label authorizationLabel; - - /// <summary> - /// getNameButton control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Button getNameButton; - - /// <summary> - /// nameLabel control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Label nameLabel; - - /// <summary> - /// getAgeButton control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Button getAgeButton; - - /// <summary> - /// ageLabel control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Label ageLabel; - - /// <summary> - /// getFavoriteSites control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Button getFavoriteSites; - - /// <summary> - /// favoriteSitesLabel control. - /// </summary> - /// <remarks> - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// </remarks> - protected global::System.Web.UI.WebControls.Label favoriteSitesLabel; - } -} diff --git a/samples/OAuthConsumer/SampleWcf2.aspx b/samples/OAuthConsumer/SampleWcf2.aspx index 797a2fc..0e58c74 100644 --- a/samples/OAuthConsumer/SampleWcf2.aspx +++ b/samples/OAuthConsumer/SampleWcf2.aspx @@ -7,7 +7,7 @@ <asp:ListItem Value="http://tempuri.org/IDataApi/GetAge">GetAge</asp:ListItem> <asp:ListItem Value="http://tempuri.org/IDataApi/GetFavoriteSites">GetFavoriteSites</asp:ListItem> </asp:CheckBoxList> - <asp:Button ID="getAuthorizationButton" runat="server" Text="Get Authorization" OnClick="getAuthorizationButton_Click" /> + <asp:Button ID="getAuthorizationButton" runat="server" Text="Request Authorization" OnClick="getAuthorizationButton_Click" /> <asp:Label ID="authorizationLabel" runat="server" /> </fieldset> <br /> diff --git a/samples/OAuthConsumer/SampleWcf2.aspx.cs b/samples/OAuthConsumer/SampleWcf2.aspx.cs index deef073..7978f91 100644 --- a/samples/OAuthConsumer/SampleWcf2.aspx.cs +++ b/samples/OAuthConsumer/SampleWcf2.aspx.cs @@ -19,8 +19,8 @@ /// The details about the sample OAuth-enabled WCF service that this sample client calls into. /// </summary> private static AuthorizationServerDescription AuthServerDescription = new AuthorizationServerDescription { - TokenEndpoint = new Uri("http://localhost:65169/OAuth2.ashx/token"), - AuthorizationEndpoint = new Uri("http://localhost:65169/OAuth2.ashx/auth"), + TokenEndpoint = new Uri("http://localhost:65169/OAuth.ashx"), + AuthorizationEndpoint = new Uri("http://localhost:65169/Members/Authorize.aspx"), }; /// <summary> @@ -55,6 +55,7 @@ if (authorization != null) { // We are receiving an authorization response. Store it and associate it with this user. Authorization = authorization; + Response.Redirect(Request.Path); // get rid of the /?code= parameter } } } diff --git a/samples/OAuthServiceProvider/Code/OAuthConsumer.cs b/samples/OAuthServiceProvider/Code/Client.cs index bf97950..43e282d 100644 --- a/samples/OAuthServiceProvider/Code/OAuthConsumer.cs +++ b/samples/OAuthServiceProvider/Code/Client.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="OAuthConsumer.cs" company="Andrew Arnott"> +// <copyright file="Client.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- diff --git a/samples/OAuthServiceProvider/Code/DataClasses.dbml b/samples/OAuthServiceProvider/Code/DataClasses.dbml index e3c9097..906d91d 100644 --- a/samples/OAuthServiceProvider/Code/DataClasses.dbml +++ b/samples/OAuthServiceProvider/Code/DataClasses.dbml @@ -1,5 +1,5 @@ <?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" /> + <Connection Mode="WebSettings" ConnectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database4.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" /> @@ -8,7 +8,7 @@ <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="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="UserId" OtherKey="UserId" Type="ClientAuthorization" /> + <Association Name="User_ClientAuthorization" Member="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="UserId" OtherKey="UserId" Type="ClientAuthorization" /> </Type> </Table> <Table Name="dbo.FavoriteSite" Member="FavoriteSites"> @@ -19,29 +19,29 @@ <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="Clients"> + <Table Name="dbo.Client" Member="Clients"> <Type Name="Client"> - <Column Name="ConsumerId" Member="ClientId" Storage="_ConsumerId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> - <Column Name="ConsumerKey" Member="ClientIdentifier" Storage="_ConsumerKey" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> - <Column Name="ConsumerSecret" Member="ClientSecret" Storage="_ConsumerSecret" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="ClientId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> + <Column Name="ClientIdentifier" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> + <Column Name="ClientSecret" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> <Column Name="Callback" Type="System.String" CanBeNull="true" /> - <Column Name="" Member="Name" Storage="_VerificationCodeLength" Type="System.String" CanBeNull="false" /> - <Association Name="OAuthConsumer_OAuthToken" Member="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="ClientId" OtherKey="ClientId" Type="ClientAuthorization" /> + <Column Name="Name" Type="System.String" CanBeNull="false" /> + <Association Name="Client_ClientAuthorization" Member="ClientAuthorizations" Storage="_OAuthTokens" ThisKey="ClientId" OtherKey="ClientId" Type="ClientAuthorization" /> </Type> </Table> - <Table Name="dbo.OAuthToken" Member="ClientAuthorizations"> + <Table Name="dbo.ClientAuthorization" Member="ClientAuthorizations"> <Type Name="ClientAuthorization"> - <Column Name="TokenId" Member="AuthorizationId" Storage="_TokenId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> - <Column Name="IssueDate" Member="CreatedOn" Storage="_IssueDate" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> - <Column Name="ConsumerId" Member="ClientId" Storage="_ConsumerId" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" /> + <Column Name="AuthorizationId" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> + <Column Name="CreatedOnUtc" Storage="_IssueDate" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> + <Column Name="ClientId" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" /> <Column Name="UserId" Type="System.Int32" DbType="Int" CanBeNull="true" /> <Column Name="Scope" Type="System.String" DbType="nvarchar(MAX)" CanBeNull="false" /> - <Column Name="RequestTokenVerifier" Member="ExpirationDate" Storage="_RequestTokenVerifier" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" /> - <Association Name="OAuthConsumer_OAuthToken" Member="Client" Storage="_OAuthConsumer" ThisKey="ClientId" OtherKey="ClientId" Type="Client" IsForeignKey="true" DeleteRule="CASCADE" DeleteOnNull="true" /> - <Association Name="User_OAuthToken" Member="User" ThisKey="UserId" OtherKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" /> + <Column Name="ExpirationDateUtc" Type="System.DateTime" DbType="DateTime NULL" CanBeNull="true" /> + <Association Name="Client_ClientAuthorization" Member="Client" ThisKey="ClientId" OtherKey="ClientId" Type="Client" IsForeignKey="true" DeleteRule="CASCADE" DeleteOnNull="true" /> + <Association Name="User_ClientAuthorization" Member="User" ThisKey="UserId" OtherKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" /> </Type> </Table> - <Table Name="" Member="Nonces"> + <Table Name="dbo.Nonce" Member="Nonces"> <Type Name="Nonce"> <Column Name="Context" Type="System.String" IsPrimaryKey="true" CanBeNull="false" /> <Column Name="Code" Type="System.String" IsPrimaryKey="true" CanBeNull="false" /> diff --git a/samples/OAuthServiceProvider/Code/DataClasses.dbml.layout b/samples/OAuthServiceProvider/Code/DataClasses.dbml.layout index e300457..346bb49 100644 --- a/samples/OAuthServiceProvider/Code/DataClasses.dbml.layout +++ b/samples/OAuthServiceProvider/Code/DataClasses.dbml.layout @@ -33,25 +33,25 @@ <classShapeMoniker Id="8a79b099-7f87-4766-907a-db2c3e1b5716" /> </nodes> </associationConnector> - <associationConnector edgePoints="[(2.5 : 4.29409912109375); (3.5 : 4.29409912109375)]" fixedFrom="Algorithm" fixedTo="Algorithm"> - <AssociationMoniker Name="/DataClassesDataContext/Client/OAuthConsumer_OAuthToken" /> + <classShape Id="a63562a7-acf2-4ed9-9686-52a1ad85633e" absoluteBounds="1.375, 6.375, 2, 1.3862939453124996"> + <DataClassMoniker Name="/DataClassesDataContext/Nonce" /> + <nestedChildShapes> + <elementListCompartment Id="9e4514ef-bc7b-4179-88e6-05363bf6ee5e" absoluteBounds="1.39, 6.835, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" /> + </nestedChildShapes> + </classShape> + <associationConnector edgePoints="[(2.5 : 4.29409912109375); (3.5 : 4.29409912109375)]" fixedFrom="NotFixed" fixedTo="NotFixed"> + <AssociationMoniker Name="/DataClassesDataContext/Client/Client_ClientAuthorization" /> <nodes> <classShapeMoniker Id="f909becb-85b1-4fe6-bb16-3feb3e4fe3ee" /> <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> </nodes> </associationConnector> - <associationConnector edgePoints="[(2.42590266277457 : 2.27089680989583); (2.42590266277457 : 3.25); (2.75 : 3.25); (2.75 : 3.67829756054687); (3.5 : 3.67829756054687)]" fixedFrom="Caller" fixedTo="Algorithm"> - <AssociationMoniker Name="/DataClassesDataContext/User/User_OAuthToken" /> + <associationConnector edgePoints="[(2.59375 : 2.27089680989583); (2.59375 : 3.28125); (3.5 : 3.28125)]" fixedFrom="NotFixed" fixedTo="NotFixed"> + <AssociationMoniker Name="/DataClassesDataContext/User/User_ClientAuthorization" /> <nodes> <classShapeMoniker Id="696d2c69-040e-411d-9257-bb664b743834" /> <classShapeMoniker Id="895ebbc8-8352-4c04-9e53-b8e6c8302d36" /> </nodes> </associationConnector> - <classShape Id="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/samples/OAuthServiceProvider/Code/DataClasses.designer.cs b/samples/OAuthServiceProvider/Code/DataClasses.designer.cs index eabcb1c..0f70a2c 100644 --- a/samples/OAuthServiceProvider/Code/DataClasses.designer.cs +++ b/samples/OAuthServiceProvider/Code/DataClasses.designer.cs @@ -483,21 +483,21 @@ namespace OAuthServiceProvider.Code } } - [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.OAuthConsumer")] + [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Client")] public partial class Client : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); - private int _ConsumerId; + private int _ClientId; - private string _ConsumerKey; + private string _ClientIdentifier; - private string _ConsumerSecret; + private string _ClientSecret; private string _Callback; - private string _VerificationCodeLength; + private string _Name; private EntitySet<ClientAuthorization> _OAuthTokens; @@ -523,60 +523,60 @@ namespace OAuthServiceProvider.Code OnCreated(); } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="ConsumerId", Storage="_ConsumerId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] public int ClientId { get { - return this._ConsumerId; + return this._ClientId; } set { - if ((this._ConsumerId != value)) + if ((this._ClientId != value)) { this.OnClientIdChanging(value); this.SendPropertyChanging(); - this._ConsumerId = value; + this._ClientId = value; this.SendPropertyChanged("ClientId"); this.OnClientIdChanged(); } } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="ConsumerKey", Storage="_ConsumerKey", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientIdentifier", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] public string ClientIdentifier { get { - return this._ConsumerKey; + return this._ClientIdentifier; } set { - if ((this._ConsumerKey != value)) + if ((this._ClientIdentifier != value)) { this.OnClientIdentifierChanging(value); this.SendPropertyChanging(); - this._ConsumerKey = value; + this._ClientIdentifier = value; this.SendPropertyChanged("ClientIdentifier"); this.OnClientIdentifierChanged(); } } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="ConsumerSecret", Storage="_ConsumerSecret", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientSecret", DbType="NVarChar(50) NOT NULL", CanBeNull=false)] public string ClientSecret { get { - return this._ConsumerSecret; + return this._ClientSecret; } set { - if ((this._ConsumerSecret != value)) + if ((this._ClientSecret != value)) { this.OnClientSecretChanging(value); this.SendPropertyChanging(); - this._ConsumerSecret = value; + this._ClientSecret = value; this.SendPropertyChanged("ClientSecret"); this.OnClientSecretChanged(); } @@ -603,20 +603,20 @@ namespace OAuthServiceProvider.Code } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="", Storage="_VerificationCodeLength", CanBeNull=false)] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Name", CanBeNull=false)] public string Name { get { - return this._VerificationCodeLength; + return this._Name; } set { - if ((this._VerificationCodeLength != value)) + if ((this._Name != value)) { this.OnNameChanging(value); this.SendPropertyChanging(); - this._VerificationCodeLength = value; + this._Name = value; this.SendPropertyChanged("Name"); this.OnNameChanged(); } @@ -669,25 +669,25 @@ namespace OAuthServiceProvider.Code } } - [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.OAuthToken")] + [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ClientAuthorization")] public partial class ClientAuthorization : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); - private int _TokenId; + private int _AuthorizationId; private System.DateTime _IssueDate; - private int _ConsumerId; + private int _ClientId; private System.Nullable<int> _UserId; private string _Scope; - private System.DateTime _RequestTokenVerifier; + private System.Nullable<System.DateTime> _ExpirationDateUtc; - private EntityRef<Client> _OAuthConsumer; + private EntityRef<Client> _Client; private EntityRef<User> _User; @@ -697,47 +697,47 @@ namespace OAuthServiceProvider.Code partial void OnCreated(); partial void OnAuthorizationIdChanging(int value); partial void OnAuthorizationIdChanged(); - partial void OnCreatedOnChanging(System.DateTime value); - partial void OnCreatedOnChanged(); + partial void OnCreatedOnUtcChanging(System.DateTime value); + partial void OnCreatedOnUtcChanged(); partial void OnClientIdChanging(int value); partial void OnClientIdChanged(); partial void OnUserIdChanging(System.Nullable<int> value); partial void OnUserIdChanged(); partial void OnScopeChanging(string value); partial void OnScopeChanged(); - partial void OnExpirationDateChanging(System.DateTime value); - partial void OnExpirationDateChanged(); + partial void OnExpirationDateUtcChanging(System.Nullable<System.DateTime> value); + partial void OnExpirationDateUtcChanged(); #endregion public ClientAuthorization() { - this._OAuthConsumer = default(EntityRef<Client>); + this._Client = default(EntityRef<Client>); this._User = default(EntityRef<User>); OnCreated(); } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="TokenId", Storage="_TokenId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AuthorizationId", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] public int AuthorizationId { get { - return this._TokenId; + return this._AuthorizationId; } set { - if ((this._TokenId != value)) + if ((this._AuthorizationId != value)) { this.OnAuthorizationIdChanging(value); this.SendPropertyChanging(); - this._TokenId = value; + this._AuthorizationId = value; this.SendPropertyChanged("AuthorizationId"); this.OnAuthorizationIdChanged(); } } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="IssueDate", Storage="_IssueDate", DbType="DateTime NOT NULL")] - public System.DateTime CreatedOn + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_IssueDate", DbType="DateTime NOT NULL")] + public System.DateTime CreatedOnUtc { get { @@ -747,29 +747,33 @@ namespace OAuthServiceProvider.Code { if ((this._IssueDate != value)) { - this.OnCreatedOnChanging(value); + this.OnCreatedOnUtcChanging(value); this.SendPropertyChanging(); this._IssueDate = value; - this.SendPropertyChanged("CreatedOn"); - this.OnCreatedOnChanged(); + this.SendPropertyChanged("CreatedOnUtc"); + this.OnCreatedOnUtcChanged(); } } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="ConsumerId", Storage="_ConsumerId", DbType="Int NOT NULL")] + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientId", DbType="Int NOT NULL")] public int ClientId { get { - return this._ConsumerId; + return this._ClientId; } set { - if ((this._ConsumerId != value)) + if ((this._ClientId != value)) { + if (this._Client.HasLoadedOrAssignedValue) + { + throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException(); + } this.OnClientIdChanging(value); this.SendPropertyChanging(); - this._ConsumerId = value; + this._ClientId = value; this.SendPropertyChanged("ClientId"); this.OnClientIdChanged(); } @@ -820,54 +824,54 @@ namespace OAuthServiceProvider.Code } } - [global::System.Data.Linq.Mapping.ColumnAttribute(Name="RequestTokenVerifier", Storage="_RequestTokenVerifier", DbType="DateTime NOT NULL")] - public System.DateTime ExpirationDate + [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExpirationDateUtc", DbType="DateTime NULL")] + public System.Nullable<System.DateTime> ExpirationDateUtc { get { - return this._RequestTokenVerifier; + return this._ExpirationDateUtc; } set { - if ((this._RequestTokenVerifier != value)) + if ((this._ExpirationDateUtc != value)) { - this.OnExpirationDateChanging(value); + this.OnExpirationDateUtcChanging(value); this.SendPropertyChanging(); - this._RequestTokenVerifier = value; - this.SendPropertyChanged("ExpirationDate"); - this.OnExpirationDateChanged(); + this._ExpirationDateUtc = value; + this.SendPropertyChanged("ExpirationDateUtc"); + this.OnExpirationDateUtcChanged(); } } } - [global::System.Data.Linq.Mapping.AssociationAttribute(Name="Client_ClientAuthorization", Storage="_OAuthConsumer", ThisKey="ClientId", OtherKey="ClientId", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")] + [global::System.Data.Linq.Mapping.AssociationAttribute(Name="Client_ClientAuthorization", Storage="_Client", ThisKey="ClientId", OtherKey="ClientId", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")] public Client Client { get { - return this._OAuthConsumer.Entity; + return this._Client.Entity; } set { - Client previousValue = this._OAuthConsumer.Entity; + Client previousValue = this._Client.Entity; if (((previousValue != value) - || (this._OAuthConsumer.HasLoadedOrAssignedValue == false))) + || (this._Client.HasLoadedOrAssignedValue == false))) { this.SendPropertyChanging(); if ((previousValue != null)) { - this._OAuthConsumer.Entity = null; + this._Client.Entity = null; previousValue.ClientAuthorizations.Remove(this); } - this._OAuthConsumer.Entity = value; + this._Client.Entity = value; if ((value != null)) { value.ClientAuthorizations.Add(this); - this._ConsumerId = value.ClientId; + this._ClientId = value.ClientId; } else { - this._ConsumerId = default(int); + this._ClientId = default(int); } this.SendPropertyChanged("Client"); } @@ -929,7 +933,7 @@ namespace OAuthServiceProvider.Code } } - [global::System.Data.Linq.Mapping.TableAttribute(Name="")] + [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Nonce")] public partial class Nonce : INotifyPropertyChanging, INotifyPropertyChanged { diff --git a/samples/OAuthServiceProvider/Code/Global.cs b/samples/OAuthServiceProvider/Code/Global.cs index bcfa8ae..580cbf4 100644 --- a/samples/OAuthServiceProvider/Code/Global.cs +++ b/samples/OAuthServiceProvider/Code/Global.cs @@ -46,12 +46,6 @@ get { return Global.DataContext.Users.SingleOrDefault(user => user.OpenIDClaimedIdentifier == HttpContext.Current.User.Identity.Name); } } - public static EndUserAuthorizationRequest PendingOAuth2Authorization - { - get { return HttpContext.Current.Session["authrequest"] as EndUserAuthorizationRequest; } - set { HttpContext.Current.Session["authrequest"] = value; } - } - private static DataClassesDataContext dataContextSimple { get { if (HttpContext.Current != null) { diff --git a/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs b/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs index 210e2ad..ff87267 100644 --- a/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs +++ b/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs @@ -8,6 +8,7 @@ using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OAuth2; using DotNetOpenAuth.OAuth2.ChannelElements; + using DotNetOpenAuth.OAuth2.Messages; internal class OAuth2AuthorizationServer : IAuthorizationServer { internal static readonly RSAParameters AsymmetricKey; @@ -31,7 +32,7 @@ get { return secret; } } - public DotNetOpenAuth.Messaging.Bindings.INonceStore VerificationCodeNonceStore { + public INonceStore VerificationCodeNonceStore { get { return this.nonceStore; } } @@ -52,8 +53,57 @@ #endregion public bool IsAuthorizationValid(IAuthorizationDescription authorization) { - // We don't support revoking tokens yet. - return true; + return this.IsAuthorizationValid(authorization.Scope, authorization.ClientIdentifier, authorization.UtcIssued, authorization.User); + } + + public bool CanBeAutoApproved(EndUserAuthorizationRequest authorizationRequest) { + if (authorizationRequest == null) { + throw new ArgumentNullException("authorizationRequest"); + } + + // NEVER issue an auto-approval to a client that would end up getting an access token immediately + // (without a client secret), as that would allow ANY client to spoof an approved client's identity + // and obtain unauthorized access to user data. + if (authorizationRequest.ResponseType == EndUserAuthorizationResponseType.AuthorizationCode) { + // Never issue auto-approval if the client secret is blank, since that too makes it easy to spoof + // a client's identity and obtain unauthorized access. + var requestingClient = Global.DataContext.Clients.First(c => c.ClientIdentifier == authorizationRequest.ClientIdentifier); + if (!string.IsNullOrEmpty(requestingClient.ClientSecret)) { + return this.IsAuthorizationValid( + authorizationRequest.Scope, + authorizationRequest.ClientIdentifier, + DateTime.UtcNow, + HttpContext.Current.User.Identity.Name); + } + } + + // Default to not auto-approving. + return false; + } + + private bool IsAuthorizationValid(HashSet<string> requestedScopes, string clientIdentifier, DateTime issuedUtc, string username) { + var grantedScopeStrings = from auth in Global.DataContext.ClientAuthorizations + where + auth.Client.ClientIdentifier == clientIdentifier && + auth.CreatedOnUtc <= issuedUtc && + (!auth.ExpirationDateUtc.HasValue || auth.ExpirationDateUtc.Value >= DateTime.UtcNow) && + auth.User.OpenIDClaimedIdentifier == username + select auth.Scope; + + if (!grantedScopeStrings.Any()) { + // No granted authorizations prior to the issuance of this token, so it must have been revoked. + // Even if later authorizations restore this client's ability to call in, we can't allow + // access tokens issued before the re-authorization because the revoked authorization should + // effectively and permanently revoke all access and refresh tokens. + return false; + } + + var grantedScopes = new HashSet<string>(OAuthUtilities.ScopeStringComparer); + foreach (string scope in grantedScopeStrings) { + grantedScopes.UnionWith(OAuthUtilities.SplitScopes(scope)); + } + + return requestedScopes.IsSubsetOf(grantedScopes); } } }
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/Members/Authorize2.aspx b/samples/OAuthServiceProvider/Members/Authorize.aspx index eb8322f..71c538a 100644 --- a/samples/OAuthServiceProvider/Members/Authorize2.aspx +++ b/samples/OAuthServiceProvider/Members/Authorize.aspx @@ -1,5 +1,5 @@ <%@ Page Title="Authorize Access" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" - CodeBehind="Authorize2.aspx.cs" Inherits="OAuthServiceProvider.Members.Authorize2" %> + CodeBehind="Authorize.aspx.cs" Inherits="OAuthServiceProvider.Members.Authorize2" %> <asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="server"> <asp:MultiView runat="server" ActiveViewIndex="0" ID="multiView"> diff --git a/samples/OAuthServiceProvider/Members/Authorize.aspx.cs b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs new file mode 100644 index 0000000..1a4c78e --- /dev/null +++ b/samples/OAuthServiceProvider/Members/Authorize.aspx.cs @@ -0,0 +1,76 @@ +namespace OAuthServiceProvider.Members { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Security.Cryptography; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + using Code; + + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + using DotNetOpenAuth.OAuth2.Messages; + + public partial class Authorize2 : System.Web.UI.Page { + private static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider(); + + private string AuthorizationSecret { + get { return Session["OAuthAuthorizationSecret"] as string; } + set { Session["OAuthAuthorizationSecret"] = value; } + } + + private EndUserAuthorizationRequest pendingRequest; + + private Client client; + + protected void Page_Load(object sender, EventArgs e) { + var getRequest = new HttpRequestInfo("GET", this.Request.Url, this.Request.RawUrl, new WebHeaderCollection(), null); + pendingRequest = Global.AuthorizationServer.ReadAuthorizationRequest(getRequest); + if (pendingRequest == null) { + throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request."); + } + + client = Global.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier); + + var authServer = new OAuth2AuthorizationServer(); + if (authServer.CanBeAutoApproved(pendingRequest)) { + Global.AuthorizationServer.ApproveAuthorizationRequest(pendingRequest, User.Identity.Name); + } + + if (!IsPostBack) { + this.desiredAccessLabel.Text = OAuthUtilities.JoinScopes(pendingRequest.Scope); + this.consumerLabel.Text = client.Name; + + // Generate an unpredictable secret that goes to the user agent and must come back + // with authorization to guarantee the user interacted with this page rather than + // being scripted by an evil Consumer. + var randomData = new byte[8]; + CryptoRandomDataGenerator.GetBytes(randomData); + this.AuthorizationSecret = Convert.ToBase64String(randomData); + this.OAuthAuthorizationSecToken.Value = this.AuthorizationSecret; + } + } + + protected void allowAccessButton_Click(object sender, EventArgs e) { + if (this.AuthorizationSecret != this.OAuthAuthorizationSecToken.Value) { + throw new ArgumentException(); // probably someone trying to hack in. + } + this.AuthorizationSecret = null; // clear one time use secret + this.multiView.SetActiveView(this.AuthGranted); + + client.ClientAuthorizations.Add( + new ClientAuthorization { + Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope), + User = Global.LoggedInUser, + CreatedOnUtc = DateTime.UtcNow, + }); + Global.AuthorizationServer.ApproveAuthorizationRequest(pendingRequest, User.Identity.Name); + } + + protected void denyAccessButton_Click(object sender, EventArgs e) { + Global.AuthorizationServer.RejectAuthorizationRequest(pendingRequest); + } + } +}
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/Members/Authorize2.aspx.designer.cs b/samples/OAuthServiceProvider/Members/Authorize.aspx.designer.cs index db39669..db39669 100644 --- a/samples/OAuthServiceProvider/Members/Authorize2.aspx.designer.cs +++ b/samples/OAuthServiceProvider/Members/Authorize.aspx.designer.cs diff --git a/samples/OAuthServiceProvider/Members/Authorize2.aspx.cs b/samples/OAuthServiceProvider/Members/Authorize2.aspx.cs deleted file mode 100644 index 88c3049..0000000 --- a/samples/OAuthServiceProvider/Members/Authorize2.aspx.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace OAuthServiceProvider.Members { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Security.Cryptography; - using System.Web; - using System.Web.UI; - using System.Web.UI.WebControls; - using Code; - - using DotNetOpenAuth.OAuth2; - - public partial class Authorize2 : System.Web.UI.Page { - private static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider(); - - private string AuthorizationSecret { - get { return Session["OAuthAuthorizationSecret"] as string; } - set { Session["OAuthAuthorizationSecret"] = value; } - } - - protected void Page_Load(object sender, EventArgs e) { - if (!IsPostBack) { - if (Global.PendingOAuth2Authorization == null) { - Response.Redirect("~/Members/AuthorizedConsumers.aspx"); - } else { - var pendingRequest = Global.PendingOAuth2Authorization; - this.desiredAccessLabel.Text = OAuthUtilities.JoinScopes(pendingRequest.Scope); - this.consumerLabel.Text = pendingRequest.ClientIdentifier; - - // Generate an unpredictable secret that goes to the user agent and must come back - // with authorization to guarantee the user interacted with this page rather than - // being scripted by an evil Consumer. - var randomData = new byte[8]; - CryptoRandomDataGenerator.GetBytes(randomData); - this.AuthorizationSecret = Convert.ToBase64String(randomData); - this.OAuthAuthorizationSecToken.Value = this.AuthorizationSecret; - } - } - } - - protected void allowAccessButton_Click(object sender, EventArgs e) { - if (this.AuthorizationSecret != this.OAuthAuthorizationSecToken.Value) { - throw new ArgumentException(); // probably someone trying to hack in. - } - this.AuthorizationSecret = null; // clear one time use secret - this.multiView.SetActiveView(this.AuthGranted); - - Global.AuthorizationServer.ApproveAuthorizationRequest(Global.PendingOAuth2Authorization, User.Identity.Name); - } - - protected void denyAccessButton_Click(object sender, EventArgs e) { - Global.AuthorizationServer.RejectAuthorizationRequest(Global.PendingOAuth2Authorization); - } - } -}
\ No newline at end of file diff --git a/samples/OAuthServiceProvider/OAuth.ashx b/samples/OAuthServiceProvider/OAuth.ashx new file mode 100644 index 0000000..d450ead --- /dev/null +++ b/samples/OAuthServiceProvider/OAuth.ashx @@ -0,0 +1 @@ +<%@ WebHandler Language="C#" CodeBehind="OAuth.ashx.cs" Class="OAuthServiceProvider.OAuth" %> diff --git a/samples/OAuthServiceProvider/OAuth2.ashx.cs b/samples/OAuthServiceProvider/OAuth.ashx.cs index 62aa680..b7880c9 100644 --- a/samples/OAuthServiceProvider/OAuth2.ashx.cs +++ b/samples/OAuthServiceProvider/OAuth.ashx.cs @@ -1,15 +1,10 @@ namespace OAuthServiceProvider { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; using System.Web; using System.Web.SessionState; using Code; using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth2; - public class OAuth2 : IHttpHandler, IRequiresSessionState { + public class OAuth : IHttpHandler, IRequiresSessionState { /// <summary> /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance. /// </summary> @@ -26,22 +21,8 @@ /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public void ProcessRequest(HttpContext context) { IDirectResponseProtocolMessage response; - switch (context.Request.PathInfo) { - case "/token": - if (Global.AuthorizationServer.TryPrepareAccessTokenResponse(out response)) { - Global.AuthorizationServer.Channel.Send(response); - } - break; - case "/auth": - var request = Global.AuthorizationServer.ReadAuthorizationRequest(); - if (request == null) { - throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request."); - } - - // Redirect the user to a page that requires the user to be logged in. - Global.PendingOAuth2Authorization = request; - context.Response.Redirect("~/Members/Authorize2.aspx"); - break; + if (Global.AuthorizationServer.TryPrepareAccessTokenResponse(out response)) { + Global.AuthorizationServer.Channel.Send(response); } } } diff --git a/samples/OAuthServiceProvider/OAuth2.ashx b/samples/OAuthServiceProvider/OAuth2.ashx deleted file mode 100644 index e36a105..0000000 --- a/samples/OAuthServiceProvider/OAuth2.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="OAuth2.ashx.cs" Class="OAuthServiceProvider.OAuth2" %> diff --git a/samples/OAuthServiceProvider/OAuthServiceProvider.csproj b/samples/OAuthServiceProvider/OAuthServiceProvider.csproj index f2e5cfd..2046c9b 100644 --- a/samples/OAuthServiceProvider/OAuthServiceProvider.csproj +++ b/samples/OAuthServiceProvider/OAuthServiceProvider.csproj @@ -59,7 +59,7 @@ <Content Include="favicon.ico" /> <Content Include="Global.asax" /> <Content Include="Login.aspx" /> - <Content Include="Members\Authorize2.aspx" /> + <Content Include="Members\Authorize.aspx" /> <Content Include="Members\AuthorizedConsumers.aspx" /> <Content Include="Members\Logoff.aspx" /> <Content Include="TracePage.aspx" /> @@ -71,15 +71,15 @@ <Compile Include="Default.aspx.designer.cs"> <DependentUpon>Default.aspx</DependentUpon> </Compile> - <Compile Include="Members\Authorize2.aspx.cs"> - <DependentUpon>Authorize2.aspx</DependentUpon> + <Compile Include="Members\Authorize.aspx.cs"> + <DependentUpon>Authorize.aspx</DependentUpon> <SubType>ASPXCodeBehind</SubType> </Compile> - <Compile Include="Members\Authorize2.aspx.designer.cs"> - <DependentUpon>Authorize2.aspx</DependentUpon> + <Compile Include="Members\Authorize.aspx.designer.cs"> + <DependentUpon>Authorize.aspx</DependentUpon> </Compile> - <Compile Include="OAuth2.ashx.cs"> - <DependentUpon>OAuth2.ashx</DependentUpon> + <Compile Include="OAuth.ashx.cs"> + <DependentUpon>OAuth.ashx</DependentUpon> </Compile> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="DataApi.cs"> @@ -91,7 +91,7 @@ <Compile Include="Code\Global.cs" /> <Compile Include="Code\IDataApi.cs" /> <Compile Include="Code\OAuthAuthorizationManager.cs" /> - <Compile Include="Code\OAuthConsumer.cs" /> + <Compile Include="Code\Client.cs" /> <Compile Include="Code\OAuthPrincipalAuthorizationPolicy.cs" /> <Compile Include="Code\TracePageAppender.cs" /> <Compile Include="Code\Utilities.cs" /> @@ -129,7 +129,7 @@ <SubType>Designer</SubType> </None> <Content Include="Members\Web.config" /> - <Content Include="OAuth2.ashx" /> + <Content Include="OAuth.ashx" /> </ItemGroup> <ItemGroup> <None Include="Code\DataClasses.dbml.layout"> diff --git a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs index 98b1068..8faf510 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs @@ -37,6 +37,5 @@ namespace DotNetOpenAuth.OAuth2.Messages { /// <value>The password.</value> [MessagePart(Protocol.password, IsRequired = true, AllowEmpty = true)] internal string Password { get; set; } - } } diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs index 1c9f5c4..4810dc3 100644 --- a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs +++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationRequest.cs @@ -27,7 +27,7 @@ namespace DotNetOpenAuth.OAuth2.Messages { : base(version, MessageTransport.Indirect, authorizationEndpoint) { Contract.Requires<ArgumentNullException>(authorizationEndpoint != null); Contract.Requires<ArgumentNullException>(version != null); - this.HttpMethods = HttpDeliveryMethods.GetRequest; + this.HttpMethods = HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.PostRequest; this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer); } |