summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-12-30 13:42:16 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2009-12-30 13:42:16 -0800
commit1b7a82f0bc74373cae8ab66b1cc12195c5553a18 (patch)
treee5b6f96e027b97eb53f6c41a6472da37dc28feb6
parent815ca5309b5af651e8ecf9583c31a2f86d02a1a9 (diff)
downloadDotNetOpenAuth-1b7a82f0bc74373cae8ab66b1cc12195c5553a18.zip
DotNetOpenAuth-1b7a82f0bc74373cae8ab66b1cc12195c5553a18.tar.gz
DotNetOpenAuth-1b7a82f0bc74373cae8ab66b1cc12195c5553a18.tar.bz2
Added (untested!) OAuth SP support.
-rw-r--r--projecttemplates/MvcRelyingParty/Controllers/AccountController.cs54
-rw-r--r--projecttemplates/MvcRelyingParty/Models/AccountAuthorizeModel.cs14
-rw-r--r--projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj10
-rw-r--r--projecttemplates/MvcRelyingParty/OAuth.ashx1
-rw-r--r--projecttemplates/MvcRelyingParty/OAuth.ashx.cs66
-rw-r--r--projecttemplates/MvcRelyingParty/Views/Account/Authorize.aspx63
-rw-r--r--projecttemplates/MvcRelyingParty/Views/Account/AuthorizeApproved.aspx24
-rw-r--r--projecttemplates/MvcRelyingParty/Views/Account/AuthorizeDenied.aspx13
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs20
9 files changed, 259 insertions, 6 deletions
diff --git a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
index cd954b9..cde7bbb 100644
--- a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
+++ b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
@@ -9,6 +9,8 @@
using System.Web.Security;
using System.Web.UI;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.Messages;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;
@@ -152,7 +154,7 @@
[Authorize]
public ActionResult Edit() {
- return View(GetModel());
+ return View(GetAccountInfoModel());
}
/// <summary>
@@ -175,10 +177,56 @@
Database.LoggedInUser.EmailAddressVerified = false;
}
- return PartialView("EditFields", GetModel());
+ return PartialView("EditFields", GetAccountInfoModel());
}
- private static AccountInfoModel GetModel() {
+ [Authorize]
+ public ActionResult Authorize() {
+ if (OAuthServiceProvider.PendingAuthorizationRequest == null) {
+ return RedirectToAction("Edit");
+ }
+
+ var model = new AccountAuthorizeModel {
+ ConsumerApp = OAuthServiceProvider.PendingAuthorizationConsumer.Name,
+ IsUnsafeRequest = OAuthServiceProvider.PendingAuthorizationRequest.IsUnsafeRequest,
+ };
+
+ return View(model);
+ }
+
+ [Authorize, AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
+ public ActionResult Authorize(bool isApproved) {
+ if (isApproved) {
+ var consumer = OAuthServiceProvider.PendingAuthorizationConsumer;
+ var tokenManager = OAuthServiceProvider.ServiceProvider.TokenManager;
+ var pendingRequest = OAuthServiceProvider.PendingAuthorizationRequest;
+ ITokenContainingMessage requestTokenMessage = pendingRequest;
+ var requestToken = tokenManager.GetRequestToken(requestTokenMessage.Token);
+
+ var response = OAuthServiceProvider.AuthorizePendingRequestTokenAsWebResponse();
+ if (response != null) {
+ // The consumer provided a callback URL that can take care of everything else.
+ return response.AsActionResult();
+ }
+
+ var model = new AccountAuthorizeModel {
+ ConsumerApp = consumer.Name,
+ };
+
+ if (!pendingRequest.IsUnsafeRequest) {
+ model.VerificationCode = ServiceProvider.CreateVerificationCode(consumer.VerificationCodeFormat, consumer.VerificationCodeLength);
+ requestToken.VerificationCode = model.VerificationCode;
+ tokenManager.UpdateToken(requestToken);
+ }
+
+ return View("AuthorizeApproved");
+ } else {
+ OAuthServiceProvider.PendingAuthorizationRequest = null;
+ return View("AuthorizeDenied");
+ }
+ }
+
+ private static AccountInfoModel GetAccountInfoModel() {
var model = new AccountInfoModel {
FirstName = Database.LoggedInUser.FirstName,
LastName = Database.LoggedInUser.LastName,
diff --git a/projecttemplates/MvcRelyingParty/Models/AccountAuthorizeModel.cs b/projecttemplates/MvcRelyingParty/Models/AccountAuthorizeModel.cs
new file mode 100644
index 0000000..0fbd9f4
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Models/AccountAuthorizeModel.cs
@@ -0,0 +1,14 @@
+namespace MvcRelyingParty.Models {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+
+ public class AccountAuthorizeModel {
+ public string ConsumerApp { get; set; }
+
+ public bool IsUnsafeRequest { get; set; }
+
+ public string VerificationCode { get; set; }
+ }
+}
diff --git a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
index ad6f475..ad26174 100644
--- a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
+++ b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
@@ -74,7 +74,11 @@
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
+ <Compile Include="Models\AccountAuthorizeModel.cs" />
<Compile Include="Models\AccountInfoModel.cs" />
+ <Compile Include="OAuth.ashx.cs">
+ <DependentUpon>OAuth.ashx</DependentUpon>
+ </Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Setup.aspx.cs">
<DependentUpon>Setup.aspx</DependentUpon>
@@ -121,6 +125,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <Content Include="OAuth.ashx" />
+ <Content Include="Views\Account\Authorize.aspx" />
+ <Content Include="Views\Account\AuthorizeApproved.aspx" />
+ <Content Include="Views\Account\AuthorizeDenied.aspx" />
+ </ItemGroup>
+ <ItemGroup>
<Folder Include="App_Data\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/projecttemplates/MvcRelyingParty/OAuth.ashx b/projecttemplates/MvcRelyingParty/OAuth.ashx
new file mode 100644
index 0000000..81b3d52
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/OAuth.ashx
@@ -0,0 +1 @@
+<%@ WebHandler Language="C#" CodeBehind="OAuth.ashx.cs" Class="MvcRelyingParty.OAuth" %>
diff --git a/projecttemplates/MvcRelyingParty/OAuth.ashx.cs b/projecttemplates/MvcRelyingParty/OAuth.ashx.cs
new file mode 100644
index 0000000..b9051c1
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/OAuth.ashx.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuth.ashx.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace MvcRelyingParty {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using System.Web.SessionState;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.Messages;
+ using RelyingPartyLogic;
+
+ /// <summary>
+ /// Responds to incoming OAuth Service Provider messages.
+ /// </summary>
+ public class OAuth : IHttpHandler, IRequiresSessionState {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuth"/> class.
+ /// </summary>
+ public OAuth() {
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
+ /// </summary>
+ /// <returns>
+ /// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
+ /// </returns>
+ public bool IsReusable {
+ get { return true; }
+ }
+
+ /// <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) {
+ var serviceProvider = OAuthServiceProvider.ServiceProvider;
+ var requestMessage = serviceProvider.ReadRequest(new HttpRequestInfo(context.Request));
+
+ UnauthorizedTokenRequest unauthorizedTokenRequestMessage;
+ AuthorizedTokenRequest authorizedTokenRequestMessage;
+ UserAuthorizationRequest userAuthorizationRequest;
+ if ((unauthorizedTokenRequestMessage = requestMessage as UnauthorizedTokenRequest) != null) {
+ var response = serviceProvider.PrepareUnauthorizedTokenMessage(unauthorizedTokenRequestMessage);
+ serviceProvider.Channel.Send(response);
+ } else if ((authorizedTokenRequestMessage = requestMessage as AuthorizedTokenRequest) != null) {
+ var response = serviceProvider.PrepareAccessTokenMessage(authorizedTokenRequestMessage);
+ serviceProvider.Channel.Send(response);
+ } else if ((userAuthorizationRequest = requestMessage as UserAuthorizationRequest) != null) {
+ // This is a browser opening to allow the user to authorize a request token,
+ // so redirect to the authorization page, which will automatically redirect
+ // to have the user log in if necessary.
+ OAuthServiceProvider.PendingAuthorizationRequest = userAuthorizationRequest;
+ HttpContext.Current.Response.Redirect("~/Account/Authorize");
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+}
diff --git a/projecttemplates/MvcRelyingParty/Views/Account/Authorize.aspx b/projecttemplates/MvcRelyingParty/Views/Account/Authorize.aspx
new file mode 100644
index 0000000..f1653c6
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Views/Account/Authorize.aspx
@@ -0,0 +1,63 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcRelyingParty.Models.AccountAuthorizeModel>" %>
+
+<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
+ Authorize
+</asp:Content>
+<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
+ <h2>
+ Authorize
+ </h2>
+ <div style="background-color: Yellow">
+ <b>Warning</b>: Never give your login credentials to another web site or application.
+ </div>
+ <p>
+ The
+ <%= Html.Encode(Model.ConsumerApp) %>
+ application is requesting to access the private data in your account here. Is that
+ alright with you?
+ </p>
+ <p>
+ If you grant access now, you can revoke it at any time by returning to
+ <%= Html.ActionLink("your account page", "Edit") %>.
+ </p>
+ <% using (Html.BeginForm()) { %>
+ <%= Html.AntiForgeryToken() %>
+ <%= Html.Hidden("IsApproved") %>
+ <div style="display: none" id="responseButtonsDiv">
+ <input type="submit" value="Yes" onclick="document.getElementsByName("IsApproved")[0].value = true; return true;" />
+ <input type="submit" value="No" onclick="document.getElementsByName("IsApproved")[0].value = false; return true;" />
+ </div>
+ <div id="javascriptDisabled">
+ <b>Javascript appears to be disabled in your browser. </b>This page requires Javascript
+ to be enabled to better protect your security.
+ </div>
+ <% if (Model.IsUnsafeRequest) { %>
+ <div style="background-color: red; color: white; font-weight: bold">
+ This website is registered with
+ <asp:Label runat="server" ID="serviceProviderDomainNameLabel" />
+ to make authorization requests, but has not been configured to send requests securely.
+ If you grant access but you did not initiate this request at
+ <%= Html.Encode(Model.ConsumerApp) %>, it may be possible for other users of
+ <%= Html.Encode(Model.ConsumerApp) %>
+ to access your data. We recommend you deny access unless you are certain that you
+ initiated this request directly with
+ <%= Html.Encode(Model.ConsumerApp) %>.
+ <% } %>
+
+ <script language="javascript" type="text/javascript">
+ //<![CDATA[
+ // we use HTML to hide the action buttons and Javascript to show them
+ // to protect against click-jacking in an iframe whose javascript is disabled.
+ document.getElementById('responseButtonsDiv').style.display = 'block';
+ document.getElementById('javascriptDisabled').style.display = 'none';
+
+ // Frame busting code (to protect us from being hosted in an iframe).
+ // This protects us from click-jacking.
+ if (document.location !== window.top.location) {
+ window.top.location = document.location;
+ }
+ //]]>
+ </script>
+
+ <% } %>
+</asp:Content>
diff --git a/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeApproved.aspx b/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeApproved.aspx
new file mode 100644
index 0000000..a2d91b0
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeApproved.aspx
@@ -0,0 +1,24 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcRelyingParty.Models.AccountAuthorizeModel>" %>
+
+<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
+ Authorized
+</asp:Content>
+<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
+ <h2>
+ Authorized
+ </h2>
+ <p>
+ Authorization has been granted.
+ </p>
+ <% if (!string.IsNullOrEmpty(Model.VerificationCode)) { %>
+ <p>
+ You must enter this verification code at the Consumer: <b>
+ <%= Html.Encode(Model.VerificationCode)%>
+ </b>
+ </p>
+ <% } else { %>
+ <p>
+ You may now close this window and return to the Consumer.
+ </p>
+ <% } %>
+</asp:Content>
diff --git a/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeDenied.aspx b/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeDenied.aspx
new file mode 100644
index 0000000..99bfb2a
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Views/Account/AuthorizeDenied.aspx
@@ -0,0 +1,13 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcRelyingParty.Models.AccountAuthorizeModel>" %>
+
+<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
+ AuthorizeDenied
+</asp:Content>
+<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
+ <h2>
+ AuthorizeDenied
+ </h2>
+ <p>
+ Authorization has been denied. You're free to do whatever now.
+ </p>
+</asp:Content>
diff --git a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
index 1880d80..807da2d 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
@@ -73,6 +73,22 @@ namespace RelyingPartyLogic {
}
public static void AuthorizePendingRequestToken() {
+ var response = AuthorizePendingRequestTokenAndGetResponse();
+ if (response != null) {
+ serviceProvider.Channel.Send(response);
+ }
+ }
+
+ public static OutgoingWebResponse AuthorizePendingRequestTokenAsWebResponse() {
+ var response = AuthorizePendingRequestTokenAndGetResponse();
+ if (response != null) {
+ return serviceProvider.Channel.PrepareResponse(response);
+ } else {
+ return null;
+ }
+ }
+
+ private static UserAuthorizationResponse AuthorizePendingRequestTokenAndGetResponse() {
var pendingRequest = PendingAuthorizationRequest;
if (pendingRequest == null) {
throw new InvalidOperationException("No pending authorization request to authorize.");
@@ -84,9 +100,7 @@ namespace RelyingPartyLogic {
PendingAuthorizationRequest = null;
var response = serviceProvider.PrepareAuthorizationResponse(pendingRequest);
- if (response != null) {
- serviceProvider.Channel.Send(response);
- }
+ return response;
}
/// <summary>