summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2010-05-31 08:00:50 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2010-05-31 08:00:50 -0700
commitad60330d66985c4892b7e0b7ddb424be9ca867c8 (patch)
tree5efdb30c9b14e1928828b76c8a66822779a17198
parent52a77983f11cfbb948a574585ba8069dcbcbd89b (diff)
downloadDotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.zip
DotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.tar.gz
DotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.tar.bz2
More work toward a working authorization server.
-rw-r--r--samples/OAuthConsumer/OAuthConsumer.csproj8
-rw-r--r--samples/OAuthConsumer/SampleWcf2.aspx13
-rw-r--r--samples/OAuthConsumer/SampleWcf2.aspx.cs48
-rw-r--r--samples/OAuthConsumer/SampleWcf2.aspx.designer.cs42
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml292
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml.cs6
-rw-r--r--samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs46
-rw-r--r--samples/OAuthServiceProvider/OAuth2.ashx.cs36
-rw-r--r--samples/OAuthServiceProvider/Web.config2
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj2
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.resx5
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs31
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs16
-rw-r--r--src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs3
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs12
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs84
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs75
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs1
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs21
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs34
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs6
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs4
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs7
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs6
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs12
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs15
29 files changed, 603 insertions, 247 deletions
diff --git a/samples/OAuthConsumer/OAuthConsumer.csproj b/samples/OAuthConsumer/OAuthConsumer.csproj
index 663b4cf..fa5acff 100644
--- a/samples/OAuthConsumer/OAuthConsumer.csproj
+++ b/samples/OAuthConsumer/OAuthConsumer.csproj
@@ -70,6 +70,7 @@
<Generator>WCF Proxy Generator</Generator>
<LastGenOutput>Reference.cs</LastGenOutput>
</None>
+ <Content Include="SampleWcf2.aspx" />
<Content Include="SignInWithTwitter.aspx" />
<Content Include="TracePage.aspx" />
<Content Include="Twitter.aspx" />
@@ -105,6 +106,13 @@
<Compile Include="SampleWcf.aspx.designer.cs">
<DependentUpon>SampleWcf.aspx</DependentUpon>
</Compile>
+ <Compile Include="SampleWcf2.aspx.cs">
+ <DependentUpon>SampleWcf2.aspx</DependentUpon>
+ <SubType>ASPXCodeBehind</SubType>
+ </Compile>
+ <Compile Include="SampleWcf2.aspx.designer.cs">
+ <DependentUpon>SampleWcf2.aspx</DependentUpon>
+ </Compile>
<Compile Include="Service References\SampleServiceProvider\Reference.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
diff --git a/samples/OAuthConsumer/SampleWcf2.aspx b/samples/OAuthConsumer/SampleWcf2.aspx
new file mode 100644
index 0000000..e8d672b
--- /dev/null
+++ b/samples/OAuthConsumer/SampleWcf2.aspx
@@ -0,0 +1,13 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" Inherits="OAuthConsumer.SampleWcf2" Codebehind="SampleWcf2.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>
+</asp:Content> \ No newline at end of file
diff --git a/samples/OAuthConsumer/SampleWcf2.aspx.cs b/samples/OAuthConsumer/SampleWcf2.aspx.cs
new file mode 100644
index 0000000..2361d36
--- /dev/null
+++ b/samples/OAuthConsumer/SampleWcf2.aspx.cs
@@ -0,0 +1,48 @@
+using DotNetOpenAuth.OAuthWrap;
+
+namespace OAuthConsumer {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+
+ public partial class SampleWcf2 : System.Web.UI.Page {
+ protected void Page_Load(object sender, EventArgs e) {
+ if (!IsPostBack)
+ {
+ var client = CreateClient();
+ var authorization = client.ProcessUserAuthorization();
+ if (authorization != null)
+ {
+ Response.Write("Obtained access token: " + authorization.AccessToken);
+ }
+ }
+ }
+
+ protected void getAuthorizationButton_Click(object sender, EventArgs e) {
+ var client = CreateClient();
+ var response = client.PrepareRequestUserAuthorization();
+
+ string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>()
+ where item.Selected
+ select item.Value).ToArray();
+ response.Scope = string.Join("|", scopes);
+ client.Channel.Send(response);
+ }
+
+ private static WebAppClient CreateClient() {
+ var authServerDescription = new AuthorizationServerDescription {
+ TokenEndpoint = new Uri("http://localhost:65169/OAuth2.ashx/token"),
+ AuthorizationEndpoint = new Uri("http://localhost:65169/OAuth2.ashx/auth"),
+ };
+ var client = new WebAppClient(authServerDescription)
+ {
+ ClientIdentifier = "sampleconsumer",
+ ClientSecret = "samplesecret",
+ };
+ return client;
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/OAuthConsumer/SampleWcf2.aspx.designer.cs b/samples/OAuthConsumer/SampleWcf2.aspx.designer.cs
new file mode 100644
index 0000000..3046936
--- /dev/null
+++ b/samples/OAuthConsumer/SampleWcf2.aspx.designer.cs
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+// <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 SampleWcf2 {
+
+ /// <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;
+ }
+}
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml b/samples/OAuthConsumerWpf/MainWindow.xaml
index 32cd758..69b23f6 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml
@@ -2,138 +2,138 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DotNetOpenAuth Consumer (sample)" Height="400" Width="442">
- <TabControl Name="outerTabControl" Margin="0,10,0,0">
- <TabItem Header="Google" Name="googleTab">
- <Grid Margin="5">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition />
- </Grid.RowDefinitions>
- <Button Grid.Column="1" Grid.Row="3" Name="beginAuthorizationButton" Click="beginAuthorizationButton_Click">Authorize</Button>
- <TabControl Grid.ColumnSpan="2" Grid.Row="4" Name="tabControl1" Margin="0,10,0,0">
- <TabItem Header="Gmail Contacts" Name="gmailContactsTab">
- <Grid Name="contactsGrid">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- <ColumnDefinition Width="Auto" />
- </Grid.ColumnDefinitions>
- </Grid>
- </TabItem>
- <TabItem Header="Blogger" Name="bloggerTab">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- <ColumnDefinition Width="*" />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
- <Label>Blog URL</Label>
- <TextBox Grid.Column="1" x:Name="blogUrlBox"/>
- <Label Grid.Row="1">Title</Label>
- <TextBox Grid.Row="1" Grid.Column="1" x:Name="postTitleBox">OAuth Rocks!</TextBox>
- <Label Grid.Row="2">Body</Label>
- <TextBox Grid.Row="2" Grid.Column="1" x:Name="postBodyBox" AcceptsReturn="True" AcceptsTab="True" AutoWordSelection="True" TextWrapping="WrapWithOverflow">&lt;p xmlns="http://www.w3.org/1999/xhtml"&gt;Oauth is cool&lt;/p&gt;</TextBox>
- <Button x:Name="postButton" Grid.Row="3" Grid.Column="1" Click="postButton_Click" IsEnabled="False">Post</Button>
- </Grid>
- </TabItem>
- </TabControl>
- </Grid>
- </TabItem>
- <TabItem Header="WCF sample">
- <Grid Margin="5">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition />
- </Grid.RowDefinitions>
- <Button Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Name="beginWcfAuthorizationButton" Click="beginWcfAuthorizationButton_Click">Authorize</Button>
- <Label Content="Name" Grid.Row="1" />
- <Label Grid.Row="1" Grid.Column="1" Name="wcfName" />
- <Label Content="Age" Grid.Row="2" />
- <Label Grid.Row="2" Grid.Column="1" Name="wcfAge" />
- <Label Content="Favorite sites" Grid.Row="3" />
- <Label Grid.Row="3" Grid.Column="1" Name="wcfFavoriteSites" />
- </Grid>
- </TabItem>
- <TabItem Header="Generic">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="auto" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="auto" />
- </Grid.ColumnDefinitions>
- <Label Grid.Row="0">Request Token URL</Label>
- <TextBox Grid.Column="1" x:Name="requestTokenUrlBox" />
- <ComboBox Grid.Column="2" x:Name="requestTokenHttpMethod" SelectedIndex="1">
- <ComboBox.Items>
- <ComboBoxItem>GET</ComboBoxItem>
- <ComboBoxItem>POST</ComboBoxItem>
- </ComboBox.Items>
- </ComboBox>
- <Label Grid.Row="1">Authorize URL</Label>
- <TextBox Grid.Row="1" Grid.Column="1" x:Name="authorizeUrlBox" />
- <Label Grid.Row="1" Grid.Column="2">GET</Label>
- <Label Grid.Row="2">Access Token URL</Label>
- <TextBox Grid.Row="2" Grid.Column="1" x:Name="accessTokenUrlBox" />
- <ComboBox Grid.Row="2" Grid.Column="2" x:Name="accessTokenHttpMethod" SelectedIndex="1">
- <ComboBox.Items>
- <ComboBoxItem>GET</ComboBoxItem>
- <ComboBoxItem>POST</ComboBoxItem>
- </ComboBox.Items>
- </ComboBox>
- <Label Grid.Row="3">Resource URL</Label>
- <TextBox Grid.Row="3" Grid.Column="1" x:Name="resourceUrlBox" />
- <ComboBox Grid.Row="3" Grid.Column="2" x:Name="resourceHttpMethodList" SelectedIndex="0">
- <ComboBox.Items>
- <ComboBoxItem>GET w/ header</ComboBoxItem>
- <ComboBoxItem>GET w/ querystring</ComboBoxItem>
- <ComboBoxItem>POST</ComboBoxItem>
- </ComboBox.Items>
- </ComboBox>
- <Label Grid.Row="4">Consumer key</Label>
- <TextBox Grid.Row="4" Grid.Column="1" x:Name="consumerKeyBox" Grid.ColumnSpan="2"/>
- <Label Grid.Row="5">Consumer secret</Label>
- <TextBox Grid.Row="5" Grid.Column="1" x:Name="consumerSecretBox" Grid.ColumnSpan="2"/>
- <Label Grid.Row="6">OAuth version</Label>
- <ComboBox Grid.Row="6" Grid.Column="1" SelectedIndex="1" x:Name="oauthVersion">
- <ComboBox.Items>
- <ComboBoxItem>1.0</ComboBoxItem>
- <ComboBoxItem>1.0a</ComboBoxItem>
- </ComboBox.Items>
- </ComboBox>
- <Button Grid.Row="7" Grid.Column="1" x:Name="beginButton" Click="beginButton_Click">Begin</Button>
- <TextBox Grid.Column="0" Grid.Row="8" Grid.ColumnSpan="3" Name="resultsBox" IsReadOnly="True" />
- </Grid>
- </TabItem>
- <TabItem Header="Generic WRAP">
+ <TabControl Name="outerTabControl" Margin="0,10,0,0">
+ <TabItem Header="Google" Name="googleTab">
+ <Grid Margin="5">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition />
+ </Grid.RowDefinitions>
+ <Button Grid.Column="1" Grid.Row="3" Name="beginAuthorizationButton" Click="beginAuthorizationButton_Click">Authorize</Button>
+ <TabControl Grid.ColumnSpan="2" Grid.Row="4" Name="tabControl1" Margin="0,10,0,0">
+ <TabItem Header="Gmail Contacts" Name="gmailContactsTab">
+ <Grid Name="contactsGrid">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ </Grid>
+ </TabItem>
+ <TabItem Header="Blogger" Name="bloggerTab">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="*" />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ </Grid.RowDefinitions>
+ <Label>Blog URL</Label>
+ <TextBox Grid.Column="1" x:Name="blogUrlBox"/>
+ <Label Grid.Row="1">Title</Label>
+ <TextBox Grid.Row="1" Grid.Column="1" x:Name="postTitleBox">OAuth Rocks!</TextBox>
+ <Label Grid.Row="2">Body</Label>
+ <TextBox Grid.Row="2" Grid.Column="1" x:Name="postBodyBox" AcceptsReturn="True" AcceptsTab="True" AutoWordSelection="True" TextWrapping="WrapWithOverflow">&lt;p xmlns="http://www.w3.org/1999/xhtml"&gt;Oauth is cool&lt;/p&gt;</TextBox>
+ <Button x:Name="postButton" Grid.Row="3" Grid.Column="1" Click="postButton_Click" IsEnabled="False">Post</Button>
+ </Grid>
+ </TabItem>
+ </TabControl>
+ </Grid>
+ </TabItem>
+ <TabItem Header="WCF sample">
+ <Grid Margin="5">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition />
+ </Grid.RowDefinitions>
+ <Button Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Name="beginWcfAuthorizationButton" Click="beginWcfAuthorizationButton_Click">Authorize</Button>
+ <Label Content="Name" Grid.Row="1" />
+ <Label Grid.Row="1" Grid.Column="1" Name="wcfName" />
+ <Label Content="Age" Grid.Row="2" />
+ <Label Grid.Row="2" Grid.Column="1" Name="wcfAge" />
+ <Label Content="Favorite sites" Grid.Row="3" />
+ <Label Grid.Row="3" Grid.Column="1" Name="wcfFavoriteSites" />
+ </Grid>
+ </TabItem>
+ <TabItem Header="Generic 1.0(a)">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="*" />
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="auto" />
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="auto" />
+ </Grid.ColumnDefinitions>
+ <Label Grid.Row="0">Request Token URL</Label>
+ <TextBox Grid.Column="1" x:Name="requestTokenUrlBox" />
+ <ComboBox Grid.Column="2" x:Name="requestTokenHttpMethod" SelectedIndex="1">
+ <ComboBox.Items>
+ <ComboBoxItem>GET</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="1">Authorize URL</Label>
+ <TextBox Grid.Row="1" Grid.Column="1" x:Name="authorizeUrlBox" />
+ <Label Grid.Row="1" Grid.Column="2">GET</Label>
+ <Label Grid.Row="2">Access Token URL</Label>
+ <TextBox Grid.Row="2" Grid.Column="1" x:Name="accessTokenUrlBox" />
+ <ComboBox Grid.Row="2" Grid.Column="2" x:Name="accessTokenHttpMethod" SelectedIndex="1">
+ <ComboBox.Items>
+ <ComboBoxItem>GET</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="3">Resource URL</Label>
+ <TextBox Grid.Row="3" Grid.Column="1" x:Name="resourceUrlBox" />
+ <ComboBox Grid.Row="3" Grid.Column="2" x:Name="resourceHttpMethodList" SelectedIndex="0">
+ <ComboBox.Items>
+ <ComboBoxItem>GET w/ header</ComboBoxItem>
+ <ComboBoxItem>GET w/ querystring</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="4">Consumer key</Label>
+ <TextBox Grid.Row="4" Grid.Column="1" x:Name="consumerKeyBox" Grid.ColumnSpan="2"/>
+ <Label Grid.Row="5">Consumer secret</Label>
+ <TextBox Grid.Row="5" Grid.Column="1" x:Name="consumerSecretBox" Grid.ColumnSpan="2"/>
+ <Label Grid.Row="6">OAuth version</Label>
+ <ComboBox Grid.Row="6" Grid.Column="1" SelectedIndex="1" x:Name="oauthVersion">
+ <ComboBox.Items>
+ <ComboBoxItem>1.0</ComboBoxItem>
+ <ComboBoxItem>1.0a</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Button Grid.Row="7" Grid.Column="1" x:Name="beginButton" Click="beginButton_Click">Begin</Button>
+ <TextBox Grid.Column="0" Grid.Row="8" Grid.ColumnSpan="3" Name="resultsBox" IsReadOnly="True" />
+ </Grid>
+ </TabItem>
+ <TabItem Header="Generic 2.0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
@@ -151,15 +151,23 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
- <Label Grid.Row="0">Access Token URL</Label>
- <TextBox Grid.Column="1" x:Name="wrapAccessTokenUrlBox" />
+ <Label Grid.Row="0">Token Endpoint URL</Label>
+ <TextBox Grid.Column="1" x:Name="wrapTokenUrlBox" />
<Label Grid.Column="2">POST</Label>
- <Label Grid.Row="1">Refresh Token URL</Label>
- <TextBox Grid.Row="1" Grid.Column="1" x:Name="wrapRefreshTokenUrlBox" />
- <Label Grid.Row="1" Grid.Column="2">POST</Label>
- <Label Grid.Row="2">User Authorization URL</Label>
- <TextBox Grid.Row="2" Grid.Column="1" x:Name="wrapUserAuthorizationUrlBox" />
- <Label Grid.Row="2" Grid.Column="2">GET</Label>
+ <Label Grid.Row="1">User Authorization URL</Label>
+ <TextBox Grid.Row="1" Grid.Column="1" x:Name="wrapAuthorizationUrlBox" />
+ <Label Grid.Row="1" Grid.Column="2">GET</Label>
+ <Label Grid.Row="2">Flow</Label>
+ <ComboBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" x:Name="flowBox" SelectedIndex="0">
+ <ComboBox.Items>
+ <ComboBoxItem>Web Server</ComboBoxItem>
+ <ComboBoxItem>Device</ComboBoxItem>
+ <ComboBoxItem>User Agent</ComboBoxItem>
+ <ComboBoxItem>Username and Password</ComboBoxItem>
+ <ComboBoxItem>Assertion</ComboBoxItem>
+ <ComboBoxItem>Client Credentials</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
<Label Grid.Row="3">Resource URL</Label>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="wrapResourceUrlBox" />
<ComboBox Grid.Row="3" Grid.Column="2" x:Name="wrapResourceHttpMethodList" SelectedIndex="0">
@@ -173,10 +181,10 @@
<TextBox Grid.Row="4" Grid.Column="1" x:Name="wrapClientIdentifierBox" Grid.ColumnSpan="2"/>
<Label Grid.Row="5">Client Secret</Label>
<TextBox Grid.Row="5" Grid.Column="1" x:Name="wrapClientSecretBox" Grid.ColumnSpan="2"/>
- <Label Grid.Row="6">WRAP version</Label>
+ <Label Grid.Row="6">OAuth 2.0 version</Label>
<ComboBox Grid.Row="6" Grid.Column="1" SelectedIndex="0" x:Name="wrapVersion">
<ComboBox.Items>
- <ComboBoxItem>1.0 early DRAFT</ComboBoxItem>
+ <ComboBoxItem>2.0 DRAFT 5</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
<Button Grid.Row="7" Grid.Column="1" x:Name="wrapBeginButton" Click="wrapBeginButton_Click">Begin</Button>
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml.cs b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
index 24d5249..92c9a6b 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml.cs
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
@@ -200,6 +200,12 @@
}
private void wrapBeginButton_Click(object sender, RoutedEventArgs e) {
+ var authServer = new DotNetOpenAuth.OAuthWrap.AuthorizationServerDescription {
+ TokenEndpoint = new Uri(wrapTokenUrlBox.Text),
+ AuthorizationEndpoint = new Uri(wrapAuthorizationUrlBox.Text),
+ };
+ //var client = new DotNetOpenAuth.OAuthWrap.WebAppClient(authServer);
+ //client.PrepareRequestUserAuthorization();
}
}
}
diff --git a/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs b/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs
index be6f885..15d791e 100644
--- a/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs
+++ b/samples/OAuthServiceProvider/Code/OAuth2AuthorizationServer.cs
@@ -1,4 +1,5 @@
-using DotNetOpenAuth.OAuth.ChannelElements;
+using DotNetOpenAuth.Messaging.Bindings;
+using DotNetOpenAuth.OAuth.ChannelElements;
namespace OAuthServiceProvider.Code {
using System;
@@ -8,47 +9,28 @@ namespace OAuthServiceProvider.Code {
using DotNetOpenAuth.OAuthWrap;
internal class OAuth2AuthorizationServer : IAuthorizationServer {
+ private static readonly byte[] secret = new byte[] { 0x33, 0x55 }; // TODO: make this cryptographically strong and unique per app.
+ private readonly INonceStore nonceStore = new DatabaseNonceStore();
#region Implementation of IAuthorizationServer
- public IConsumerDescription GetClient(string clientIdentifier)
- {
- throw new NotImplementedException();
- }
-
- #endregion
-
public byte[] Secret {
- get { throw new NotImplementedException(); }
+ get { return secret; }
}
public DotNetOpenAuth.Messaging.Bindings.INonceStore VerificationCodeNonceStore {
- get { throw new NotImplementedException(); }
+ get { return this.nonceStore; }
}
- private class ConsumerDescription : IConsumerDescription {
- public string Key {
- get { throw new NotImplementedException(); }
- }
-
- public string Secret {
- get { throw new NotImplementedException(); }
- }
-
- public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate {
- get { throw new NotImplementedException(); }
+ public IConsumerDescription GetClient(string clientIdentifier) {
+ var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault(
+ consumerCandidate => consumerCandidate.ConsumerKey == clientIdentifier);
+ if (consumerRow == null) {
+ throw new ArgumentOutOfRangeException("clientIdentifier");
}
- public Uri Callback {
- get { throw new NotImplementedException(); }
- }
-
- public DotNetOpenAuth.OAuth.VerificationCodeFormat VerificationCodeFormat {
- get { throw new NotImplementedException(); }
- }
-
- public int VerificationCodeLength {
- get { throw new NotImplementedException(); }
- }
+ return consumerRow;
}
+
+ #endregion
}
} \ No newline at end of file
diff --git a/samples/OAuthServiceProvider/OAuth2.ashx.cs b/samples/OAuthServiceProvider/OAuth2.ashx.cs
index 17586be..cd76254 100644
--- a/samples/OAuthServiceProvider/OAuth2.ashx.cs
+++ b/samples/OAuthServiceProvider/OAuth2.ashx.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Net;
using System.Web;
+ using System.Web.SessionState;
using Code;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuthWrap;
@@ -11,29 +12,34 @@
/// <summary>
/// Summary description for OAuth2
/// </summary>
- public class OAuth2 : IHttpHandler {
+ public class OAuth2 : IHttpHandler, IRequiresSessionState {
/// <summary>
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
/// </summary>
/// <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;
- if (Global.AuthorizationServer.TryPrepareAccessTokenResponse(out response)) {
- Global.AuthorizationServer.Channel.Send(response);
- } else {
- var request = Global.AuthorizationServer.ReadAuthorizationRequest();
- if (request == null) {
- throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
- }
+ 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.");
+ }
- // This sample doesn't implement support for immediate mode.
- if (!request.IsUserInteractionAllowed) {
- Global.AuthorizationServer.RejectAuthorizationRequest(request);
- }
+ // This sample doesn't implement support for immediate mode.
+ if (!request.IsUserInteractionAllowed) {
+ Global.AuthorizationServer.RejectAuthorizationRequest(request);
+ }
- // Redirect the user to a page that requires the user to be logged in.
- Global.PendingOAuth2Authorization = request;
- context.Response.Redirect("~/Members/Authorize2.aspx");
+ // Redirect the user to a page that requires the user to be logged in.
+ Global.PendingOAuth2Authorization = request;
+ context.Response.Redirect("~/Members/Authorize2.aspx");
+ break;
}
}
diff --git a/samples/OAuthServiceProvider/Web.config b/samples/OAuthServiceProvider/Web.config
index dc440fd..9a53b4a 100644
--- a/samples/OAuthServiceProvider/Web.config
+++ b/samples/OAuthServiceProvider/Web.config
@@ -43,7 +43,7 @@
<appSettings/>
<connectionStrings>
- <add name="DatabaseConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True"
+ <add name="DatabaseConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database3.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index d282777..bdfb911 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -308,12 +308,14 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="Messaging\StandardMessageFactory.cs" />
<Compile Include="OAuthWrap\AuthorizationServerBase.cs" />
<Compile Include="OAuthWrap\AuthorizationState.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\AuthServerBindingElementBase.cs" />
<Compile Include="OAuthWrap\ChannelElements\IAccessTokenRequest.cs" />
<Compile Include="OAuthWrap\ChannelElements\OAuthWrapResourceServerChannel.cs" />
<Compile Include="Messaging\StandardMessageFactoryChannel.cs" />
<Compile Include="OAuthWrap\ChannelElements\TimestampEncoder.cs" />
<Compile Include="OAuthWrap\ChannelElements\VerificationCode.cs" />
<Compile Include="OAuthWrap\ChannelElements\WebAppVerificationCodeBindingElement.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\AuthServerWebServerFlowBindingElement.cs" />
<Compile Include="OAuthWrap\IAccessTokenAnalyzer.cs" />
<Compile Include="OAuthWrap\IAuthorizationServer.cs" />
<Compile Include="OAuthWrap\IAuthorizationState.cs" />
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
index 1be62f5..21fd53a 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.1
+// Runtime Version:4.0.30426.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -349,6 +349,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to The following message parts had constant value requirements that were unsatisfied: {0}.
+ /// </summary>
+ internal static string RequiredMessagePartConstantIncorrect {
+ get {
+ return ResourceManager.GetString("RequiredMessagePartConstantIncorrect", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The following required non-empty parameters were empty in the {0} message: {1}.
/// </summary>
internal static string RequiredNonEmptyParameterWasEmpty {
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
index cb80442..3a265f1 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
@@ -306,4 +306,7 @@
<data name="StandardMessageFactoryUnsupportedMessageType" xml:space="preserve">
<value>This message factory does not support message type(s): {0}</value>
</data>
-</root>
+ <data name="RequiredMessagePartConstantIncorrect" xml:space="preserve">
+ <value>The following message parts had constant value requirements that were unsatisfied: {0}</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
index 17b5304..808d5b8 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
@@ -93,6 +93,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
try {
this.CheckRequiredMessagePartsArePresent(parts.Keys, true);
this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, true);
+ this.CheckMessagePartsConstantValues(parts, true);
} catch (ProtocolException) {
Logger.Messaging.ErrorFormat(
"Error while performing basic validation of {0} with these message parts:{1}{2}",
@@ -112,7 +113,8 @@ namespace DotNetOpenAuth.Messaging.Reflection {
Contract.Requires<ArgumentNullException>(parts != null);
return this.CheckRequiredMessagePartsArePresent(parts.Keys, false) &&
- this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, false);
+ this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, false) &&
+ this.CheckMessagePartsConstantValues(parts, false);
}
/// <summary>
@@ -185,6 +187,33 @@ namespace DotNetOpenAuth.Messaging.Reflection {
return true;
}
+ private bool CheckMessagePartsConstantValues(IDictionary<string, string> partValues, bool throwOnFailure)
+ {
+ Contract.Requires<ArgumentNullException>(partValues != null);
+
+ var badConstantValues = (from part in this.Mapping.Values
+ where part.IsConstantValueAvailableStatically
+ where partValues.ContainsKey(part.Name)
+ where !string.Equals(partValues[part.Name], part.StaticConstantValue, StringComparison.Ordinal)
+ select part.Name).ToArray();
+ if (badConstantValues.Length > 0) {
+ if (throwOnFailure) {
+ ErrorUtilities.ThrowProtocol(
+ MessagingStrings.RequiredMessagePartConstantIncorrect,
+ this.MessageType.FullName,
+ string.Join(", ", badConstantValues));
+ } else {
+ Logger.Messaging.DebugFormat(
+ MessagingStrings.RequiredMessagePartConstantIncorrect,
+ this.MessageType.FullName,
+ badConstantValues.ToStringDeferred());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/// <summary>
/// Reflects over some <see cref="IMessage"/>-implementing type
/// and prepares to serialize/deserialize instances of that type.
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
index 4590c44..a9ec171 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
@@ -159,6 +159,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
(this.field.Attributes & FieldAttributes.InitOnly) == FieldAttributes.InitOnly ||
(this.field.Attributes & constAttributes) == constAttributes)) {
this.IsConstantValue = true;
+ this.IsConstantValueAvailableStatically = this.field.IsStatic;
} else if (this.property != null && !this.property.CanWrite) {
this.IsConstantValue = true;
}
@@ -194,6 +195,21 @@ namespace DotNetOpenAuth.Messaging.Reflection {
internal bool IsConstantValue { get; set; }
/// <summary>
+ /// Gets or sets a value indicating whether this part is defined as a constant field and can be read without a message instance.
+ /// </summary>
+ internal bool IsConstantValueAvailableStatically { get; set; }
+
+ /// <summary>
+ /// Gets the static constant value for this message part without a message instance.
+ /// </summary>
+ internal string StaticConstantValue {
+ get {
+ Contract.Requires<InvalidOperationException>(this.IsConstantValueAvailableStatically);
+ return this.ToString(this.field.GetValue(null));
+ }
+ }
+
+ /// <summary>
/// Sets the member of a given message to some given value.
/// Used in deserialization.
/// </summary>
diff --git a/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs b/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
index abf3359..2eacf93 100644
--- a/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
+++ b/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
@@ -144,7 +144,8 @@ namespace DotNetOpenAuth.Messaging {
var matches = this.requestMessageTypes.Keys
.Where(message => message.CheckMessagePartsPassBasicValidation(fields))
- .OrderByDescending(message => message.Mapping.Count)
+ .OrderByDescending(message => CountInCommon(message.Mapping.Keys, fields.Keys))
+ .ThenByDescending(message => message.Mapping.Count)
.CacheGeneratedResults();
var match = matches.FirstOrDefault();
if (match != null) {
diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
index 1875bd1..f6f2041 100644
--- a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
@@ -18,6 +18,7 @@ namespace DotNetOpenAuth.OAuthWrap {
protected AuthorizationServerBase(IAuthorizationServer authorizationServer) {
Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer");
this.AuthorizationServer = authorizationServer;
+ this.Channel = new OAuthWrapAuthorizationServerChannel(authorizationServer);
}
public Channel Channel { get; set; }
@@ -27,16 +28,5 @@ namespace DotNetOpenAuth.OAuthWrap {
}
public IAuthorizationServer AuthorizationServer { get; set; }
-
- protected IConsumerDescription GetClient(string clientIdentifier) {
- Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier));
- Contract.Ensures(Contract.Result<IConsumerDescription>() != null);
-
- try {
- return this.AuthorizationServer.GetClient(clientIdentifier);
- } catch (KeyNotFoundException ex) {
- throw ErrorUtilities.Wrap(ex, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
- }
- }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs
new file mode 100644
index 0000000..c84d37d
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthServerBindingElementBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Messaging;
+
+ internal abstract class AuthServerBindingElementBase : IChannelBindingElement {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthServerBindingElementBase"/> class.
+ /// </summary>
+ protected AuthServerBindingElementBase()
+ {
+ }
+
+ /// <summary>
+ /// Gets or sets the channel that this binding element belongs to.
+ /// </summary>
+ /// <remarks>
+ /// This property is set by the channel when it is first constructed.
+ /// </remarks>
+ public Channel Channel { get; set; }
+
+ protected OAuthWrapAuthorizationServerChannel OAuthChannel {
+ get { return (OAuthWrapAuthorizationServerChannel)this.Channel; }
+ }
+
+ /// <summary>
+ /// Gets the authorization server hosting this channel.
+ /// </summary>
+ /// <value>The authorization server.</value>
+ protected IAuthorizationServer AuthorizationServer {
+ get { return this.OAuthChannel.AuthorizationServer; }
+ }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public abstract MessageProtections Protection { get; }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public abstract MessageProtections? ProcessOutgoingMessage(IProtocolMessage message);
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public abstract MessageProtections? ProcessIncomingMessage(IProtocolMessage message);
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs
new file mode 100644
index 0000000..2f7b49e
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------
+// <copyright file="WebServerFlowBindingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OAuthWrap.Messages;
+ using Messaging;
+
+ internal class AuthServerWebServerFlowBindingElement : AuthServerBindingElementBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthServerWebServerFlowBindingElement"/> class.
+ /// </summary>
+ internal AuthServerWebServerFlowBindingElement() {
+ }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public override MessageProtections Protection {
+ get { return MessageProtections.None; }
+ }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ return null;
+ }
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ var authorizationRequest = message as WebAppRequest;
+ if (authorizationRequest != null) {
+ var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier);
+ ErrorUtilities.VerifyProtocol(client.Callback == null || client.Callback == authorizationRequest.Callback, OAuthWrapStrings.CallbackMismatch, client.Callback, authorizationRequest.Callback);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
index aae511d..f286e4d 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
@@ -161,6 +161,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
var bindingElements = new List<IChannelBindingElement>();
if (authorizationServer != null) {
+ bindingElements.Add(new AuthServerWebServerFlowBindingElement());
bindingElements.Add(new WebAppVerificationCodeBindingElement());
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
index 3a46517..e99a685 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
@@ -20,13 +20,14 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// </summary>
/// <param name="channel">The channel.</param>
/// <param name="callback">The callback.</param>
- internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, Uri callback, string scope)
+ internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, Uri callback, string scope, string username)
: this(channel) {
Contract.Requires<ArgumentNullException>(channel != null, "channel");
Contract.Requires<ArgumentNullException>(callback != null, "callback");
this.CallbackHash = this.CalculateCallbackHash(callback);
this.Scope = scope;
+ this.User = username;
this.CreationDateUtc = DateTime.UtcNow;
this.Nonce = Convert.ToBase64String(MessagingUtilities.GetNonCryptoRandomData(NonceLength));
}
@@ -50,10 +51,13 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
[MessagePart("cb")]
private string CallbackHash { get; set; }
- [MessagePart("scope")]
+ [MessagePart]
internal string Scope { get; set; }
- [MessagePart("nonce")]
+ [MessagePart]
+ internal string User { get; set; }
+
+ [MessagePart]
internal string Nonce { get; set; }
[MessagePart("timestamp", Encoder = typeof(TimestampEncoder))]
@@ -67,6 +71,12 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// before it passes through the channel binding elements.
/// </summary>
void IMessageWithEvents.OnSending() {
+ // Encrypt the authorizing username so as to not expose unintended private user data
+ // to the client or any eavesdropping third party.
+ if (this.User != null) {
+ // TODO: code here
+ }
+
this.Signature = CalculateSignature();
}
@@ -77,6 +87,11 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
void IMessageWithEvents.OnReceiving() {
// Verify that the verification code was issued by this authorization server.
ErrorUtilities.VerifyProtocol(string.Equals(this.Signature, this.CalculateSignature(), StringComparison.Ordinal), Protocol.bad_verification_code);
+
+ // Decrypt the authorizing username.
+ if (this.User != null) {
+ // TODO: code here
+ }
}
internal static VerificationCode Decode(OAuthWrapAuthorizationServerChannel channel, string value) {
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
index f85cf98..31639f3 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
@@ -17,7 +17,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// A binding element for OAuth 2.0 authorization servers that create/verify
/// issued verification codes as part of obtaining access/refresh tokens.
/// </summary>
- internal class WebAppVerificationCodeBindingElement : IChannelBindingElement {
+ internal class WebAppVerificationCodeBindingElement : AuthServerBindingElementBase {
private const string VerificationCodeContext = "{VerificationCode}";
/// <summary>
@@ -27,28 +27,16 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
}
/// <summary>
- /// Gets or sets the channel that this binding element belongs to.
- /// </summary>
- /// <remarks>
- /// This property is set by the channel when it is first constructed.
- /// </remarks>
- public Channel Channel { get; set; }
-
- /// <summary>
/// Gets the protection commonly offered (if any) by this binding element.
/// </summary>
/// <value>Always <c>MessageProtections.None</c></value>
/// <remarks>
/// This value is used to assist in sorting binding elements in the channel stack.
/// </remarks>
- public MessageProtections Protection {
+ public override MessageProtections Protection {
get { return MessageProtections.None; }
}
- protected OAuthWrapAuthorizationServerChannel OAuthChannel {
- get { return (OAuthWrapAuthorizationServerChannel)this.Channel; }
- }
-
/// <summary>
/// Gets the maximum message age from the standard expiration binding element.
/// </summary>
@@ -57,14 +45,6 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
}
/// <summary>
- /// Gets the authorization server hosting this channel.
- /// </summary>
- /// <value>The authorization server.</value>
- private IAuthorizationServer AuthorizationServer {
- get { return this.OAuthChannel.AuthorizationServer; }
- }
-
- /// <summary>
/// Prepares a message for sending based on the rules of this channel binding element.
/// </summary>
/// <param name="message">The message to prepare for sending.</param>
@@ -76,13 +56,13 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// Implementations that provide message protection must honor the
/// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
/// </remarks>
- public MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
var response = message as WebAppSuccessResponse;
if (response != null) {
- var directResponse = response as IDirectResponseProtocolMessage;
- var request = directResponse.OriginatingRequest as WebAppRequest;
+ var directResponse = (IDirectResponseProtocolMessage)response;
+ var request = (WebAppRequest)directResponse.OriginatingRequest;
- var code = new VerificationCode(this.OAuthChannel, request.Callback, request.Scope);
+ var code = new VerificationCode(this.OAuthChannel, request.Callback, request.Scope, response.AuthorizingUsername);
response.VerificationCode = code.Encode();
return MessageProtections.None;
@@ -108,7 +88,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// Implementations that provide message protection must honor the
/// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
/// </remarks>
- public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
var request = message as WebAppAccessTokenRequest;
if (request != null) {
var client = this.AuthorizationServer.GetClient(request.ClientIdentifier);
diff --git a/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
index c92ecc7..fccf067 100644
--- a/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
@@ -16,6 +16,12 @@ namespace DotNetOpenAuth.OAuthWrap {
[ContractClass(typeof(IAuthorizationServerContract))]
public interface IAuthorizationServer {
+ /// <summary>
+ /// Gets the client with a given identifier.
+ /// </summary>
+ /// <param name="clientIdentifier">The client identifier.</param>
+ /// <returns>The client registration. Never null.</returns>
+ /// <exception cref="ArgumentException">Thrown when no client with the given identifier is registered with this authorization server.</exception>
IConsumerDescription GetClient(string clientIdentifier);
byte[] Secret { get; }
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
index 9986d19..738846b 100644
--- a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
@@ -49,11 +49,13 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// Initializes a new instance of the <see cref="MessageBase"/> class.
/// </summary>
/// <param name="request">The originating request.</param>
- protected MessageBase(IDirectedProtocolMessage request) {
+ /// <param name="recipient">The recipient of the directed message. Null if not applicable.</param>
+ protected MessageBase(IDirectedProtocolMessage request, Uri recipient = null) {
Contract.Requires<ArgumentNullException>(request != null);
this.originatingRequest = request;
this.messageTransport = MessageTransport.Direct;
this.version = request.Version;
+ this.Recipient = recipient;
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
index e93acca..2cfb017 100644
--- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
@@ -32,7 +32,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// <param name="clientCallback">The client callback.</param>
/// <param name="request">The request.</param>
internal WebAppSuccessResponse(Uri clientCallback, WebAppRequest request)
- : this(clientCallback, ((IMessage)request).Version) {
+ : base(request, clientCallback) {
Contract.Requires<ArgumentNullException>(clientCallback != null, "clientCallback");
Contract.Requires<ArgumentNullException>(request != null, "request");
((IMessageWithClientState)this).ClientState = ((IMessageWithClientState)request).ClientState;
@@ -57,5 +57,10 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// </value>
[MessagePart(Protocol.code, IsRequired = true, AllowEmpty = true)]
internal string VerificationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the authorizing user's account name.
+ /// </summary>
+ internal string AuthorizingUsername { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
index d5836ff..35417e1 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
@@ -61,6 +61,15 @@ namespace DotNetOpenAuth.OAuthWrap {
}
/// <summary>
+ /// Looks up a localized string similar to Client&apos;s pre-registered callback URL ({0}) does not match the one found in the authorization request ({1})..
+ /// </summary>
+ internal static string CallbackMismatch {
+ get {
+ return ResourceManager.GetString("CallbackMismatch", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Failed to obtain access token. Authorization Server reports reason: {0}.
/// </summary>
internal static string CannotObtainAccessTokenWithReason {
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
index 2e70624..ae2cc6c 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
@@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="CallbackMismatch" xml:space="preserve">
+ <value>Client's pre-registered callback URL ({0}) does not match the one found in the authorization request ({1}).</value>
+ </data>
<data name="CannotObtainAccessTokenWithReason" xml:space="preserve">
<value>Failed to obtain access token. Authorization Server reports reason: {0}</value>
</data>
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
index b403f91..837d571 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
@@ -40,10 +40,11 @@ namespace DotNetOpenAuth.OAuthWrap {
return message;
}
- public void ApproveAuthorizationRequest(WebAppRequest authorizationRequest, Uri callback = null) {
+ public void ApproveAuthorizationRequest(WebAppRequest authorizationRequest, string username, Uri callback = null) {
Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, callback);
+ response.AuthorizingUsername = username;
this.Channel.Send(response);
}
@@ -59,7 +60,6 @@ namespace DotNetOpenAuth.OAuthWrap {
return this.TryPrepareAccessTokenResponse(this.Channel.GetRequestFromContext(), out response);
}
-
public bool TryPrepareAccessTokenResponse(HttpRequestInfo httpRequestInfo, out IDirectResponseProtocolMessage response)
{
Contract.Requires<ArgumentNullException>(httpRequestInfo != null, "httpRequestInfo");
@@ -95,7 +95,7 @@ namespace DotNetOpenAuth.OAuthWrap {
callback = this.GetCallback(authorizationRequest);
}
- var client = GetClient(authorizationRequest.ClientIdentifier);
+ var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier);
var response = new WebAppSuccessResponse(callback, authorizationRequest);
return response;
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
index 4ac1430..0e26994 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
@@ -64,16 +64,14 @@ namespace DotNetOpenAuth.OAuthWrap {
return request;
}
- public IAuthorizationState ProcessUserAuthorization() {
- Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
- return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext());
- }
-
- public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request) {
- Contract.Requires<ArgumentNullException>(request != null);
+ public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request = null) {
Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier));
Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientSecret));
+ if (request == null) {
+ request = this.Channel.GetRequestFromContext();
+ }
+
IMessageWithClientState response;
if (this.Channel.TryReadFromRequest<IMessageWithClientState>(request, out response)) {
Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.UrlBeforeRewriting, this.Channel.MessageDescriptions.Get(response));
diff --git a/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
index 7e04f3f..86a9c5d 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
@@ -4,6 +4,8 @@
// </copyright>
//-----------------------------------------------------------------------
+using DotNetOpenAuth.Messaging;
+
namespace DotNetOpenAuth.OAuthWrap {
using System;
using System.Collections.Generic;
@@ -30,5 +32,18 @@ namespace DotNetOpenAuth.OAuthWrap {
Protocol.HttpAuthorizationHeaderFormat,
accessToken);
}
+
+ internal static DotNetOpenAuth.OAuth.ChannelElements.IConsumerDescription GetClientOrThrow(this IAuthorizationServer authorizationServer, string clientIdentifier) {
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier));
+ Contract.Ensures(Contract.Result<DotNetOpenAuth.OAuth.ChannelElements.IConsumerDescription>() != null);
+
+ try {
+ return authorizationServer.GetClient(clientIdentifier);
+ } catch (KeyNotFoundException ex) {
+ throw ErrorUtilities.Wrap(ex, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
+ } catch (ArgumentException ex) {
+ throw ErrorUtilities.Wrap(ex, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
+ }
+ }
}
}