diff options
Diffstat (limited to 'samples/OpenIdProviderMvc')
15 files changed, 204 insertions, 38 deletions
diff --git a/samples/OpenIdProviderMvc/App_Data/Users.xml b/samples/OpenIdProviderMvc/App_Data/Users.xml index cffe009..7f70bc6 100644 --- a/samples/OpenIdProviderMvc/App_Data/Users.xml +++ b/samples/OpenIdProviderMvc/App_Data/Users.xml @@ -3,21 +3,26 @@ <User> <UserName>bob</UserName> <Password>test</Password> + <Salt>CDI=</Salt> </User> <User> <UserName>bob1</UserName> <Password>test</Password> + <Salt>CAI=</Salt> </User> <User> <UserName>bob2</UserName> <Password>test</Password> + <Salt>hYMC</Salt> </User> <User> <UserName>bob3</UserName> <Password>test</Password> + <Salt>hTKDAg==</Salt> </User> <User> <UserName>bob4</UserName> <Password>test</Password> + <Salt>hTkDAg==</Salt> </User> </Users> diff --git a/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs new file mode 100644 index 0000000..2b9e01c --- /dev/null +++ b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs @@ -0,0 +1,23 @@ +namespace OpenIdProviderMvc.Code { + using System; + using System.Web.Security; + using DotNetOpenAuth.ApplicationBlock.Provider; + using DotNetOpenAuth.OpenId; + using OpenIdProviderMvc.Models; + + internal class AnonymousIdentifierProvider : AnonymousIdentifierProviderBase { + internal AnonymousIdentifierProvider() + : base(Util.GetAppPathRootedUri("anon?id=")) { + } + + protected override byte[] GetHashSaltForLocalIdentifier(Identifier localIdentifier) { + // This is just a sample with no database... a real web app MUST return + // a reasonable salt here and have that salt be persistent for each user. + var membership = (ReadOnlyXmlMembershipProvider)Membership.Provider; + string username = User.GetUserFromClaimedIdentifier(new Uri(localIdentifier)); + string salt = membership.GetSalt(username); + return Convert.FromBase64String(salt); + ////return AnonymousIdentifierProviderBase.GetNewSalt(5); + } + } +} diff --git a/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs b/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs index 3da0f8e..d66573f 100644 --- a/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs +++ b/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs @@ -236,6 +236,13 @@ throw new NotSupportedException(); } + internal string GetSalt(string userName) { + // This is just a sample with no database... a real web app MUST return + // a reasonable salt here and have that salt be persistent for each user. + this.ReadMembershipDataStore(); + return this.users[userName].Email; + } + // Helper method private void ReadMembershipDataStore() { lock (this) { @@ -246,11 +253,13 @@ XmlNodeList nodes = doc.GetElementsByTagName("User"); foreach (XmlNode node in nodes) { + // Yes, we're misusing some of these fields. A real app would + // have the right fields from a database to use. MembershipUser user = new MembershipUser( Name, // Provider name node["UserName"].InnerText, // Username null, // providerUserKey - null, // Email + node["Salt"].InnerText, // Email string.Empty, // passwordQuestion node["Password"].InnerText, // Comment true, // isApproved diff --git a/samples/OpenIdProviderMvc/Code/Util.cs b/samples/OpenIdProviderMvc/Code/Util.cs new file mode 100644 index 0000000..6623952 --- /dev/null +++ b/samples/OpenIdProviderMvc/Code/Util.cs @@ -0,0 +1,17 @@ +namespace OpenIdProviderMvc.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + + internal static class Util { + internal static Uri GetAppPathRootedUri(string value) { + string appPath = HttpContext.Current.Request.ApplicationPath.ToLowerInvariant(); + if (!appPath.EndsWith("/")) { + appPath += "/"; + } + + return new Uri(HttpContext.Current.Request.Url, appPath + value); + } + } +} diff --git a/samples/OpenIdProviderMvc/Controllers/HomeController.cs b/samples/OpenIdProviderMvc/Controllers/HomeController.cs index 5ba08b3..346e838 100644 --- a/samples/OpenIdProviderMvc/Controllers/HomeController.cs +++ b/samples/OpenIdProviderMvc/Controllers/HomeController.cs @@ -23,5 +23,9 @@ public ActionResult Xrds() { return View(); } + + public ActionResult PpidXrds() { + return View(); + } } } diff --git a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs index f75377c..e353268 100644 --- a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs +++ b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs @@ -5,8 +5,11 @@ namespace OpenIdProviderMvc.Controllers { using System.Web; using System.Web.Mvc; using System.Web.Mvc.Ajax; + using DotNetOpenAuth.ApplicationBlock.Provider; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Provider; + using OpenIdProviderMvc.Code; public class OpenIdController : Controller { internal static OpenIdProvider OpenIdProvider = new OpenIdProvider(); @@ -16,16 +19,68 @@ namespace OpenIdProviderMvc.Controllers { set { ProviderEndpoint.PendingAuthenticationRequest = value; } } + [ValidateInput(false)] + public ActionResult PpidProvider() { + return this.DoProvider(true); + } + + [ValidateInput(false)] public ActionResult Provider() { + return this.DoProvider(false); + } + + [Authorize] + public ActionResult SendAssertion(bool pseudonymous) { + IAuthenticationRequest authReq = PendingAuthenticationRequest; + PendingAuthenticationRequest = null; + if (authReq == null) { + throw new InvalidOperationException(); + } + + Identifier localIdentifier = Models.User.GetClaimedIdentifierForUser(User.Identity.Name); + + if (pseudonymous) { + if (!authReq.IsDirectedIdentity) { + throw new InvalidOperationException("Directed identity is the only supported scenario for anonymous identifiers."); + } + + var anonProvider = new AnonymousIdentifierProvider(); + authReq.ScrubPersonallyIdentifiableInformation(localIdentifier, anonProvider, true); + authReq.IsAuthenticated = true; + } else { + if (authReq.IsDirectedIdentity) { + authReq.LocalIdentifier = localIdentifier; + authReq.ClaimedIdentifier = localIdentifier; + authReq.IsAuthenticated = true; + } else { + if (authReq.LocalIdentifier == localIdentifier) { + authReq.IsAuthenticated = true; + if (!authReq.IsDelegatedIdentifier) { + authReq.ClaimedIdentifier = authReq.LocalIdentifier; + } + } else { + authReq.IsAuthenticated = false; + } + } + + // TODO: Respond to AX/sreg extension requests here. + // We don't want to add these extension responses for anonymous identifiers + // because they could leak information about the user's identity. + } + + return OpenIdProvider.PrepareResponse(authReq).AsActionResult(); + } + + private ActionResult DoProvider(bool pseudonymous) { IRequest request = OpenIdProvider.GetRequest(); if (request != null) { var authRequest = request as IAuthenticationRequest; if (authRequest != null) { PendingAuthenticationRequest = authRequest; if (User.Identity.IsAuthenticated && (authRequest.IsDirectedIdentity || Models.User.GetClaimedIdentifierForUser(User.Identity.Name) == authRequest.LocalIdentifier)) { - return this.SendAssertion(); + return this.SendAssertion(pseudonymous); } else { - return RedirectToAction("LogOn", "Account", new { returnUrl = Url.Action("SendAssertion") }); + return RedirectToAction("LogOn", "Account", new { returnUrl = Url.Action("SendAssertion", new { pseudonymous = pseudonymous }) }); } } @@ -38,30 +93,5 @@ namespace OpenIdProviderMvc.Controllers { return View(); } } - - [Authorize] - public ActionResult SendAssertion() { - IAuthenticationRequest authReq = PendingAuthenticationRequest; - PendingAuthenticationRequest = null; - if (authReq == null) { - throw new InvalidOperationException(); - } - - if (authReq.IsDirectedIdentity) { - authReq.LocalIdentifier = Models.User.GetClaimedIdentifierForUser(User.Identity.Name); - authReq.ClaimedIdentifier = authReq.LocalIdentifier; - authReq.IsAuthenticated = true; - } else { - if (authReq.LocalIdentifier == Models.User.GetClaimedIdentifierForUser(User.Identity.Name)) { - authReq.IsAuthenticated = true; - if (!authReq.IsDelegatedIdentifier) { - authReq.ClaimedIdentifier = authReq.LocalIdentifier; - } - } else { - authReq.IsAuthenticated = false; - } - } - return OpenIdProvider.PrepareResponse(authReq).AsActionResult(); - } } } diff --git a/samples/OpenIdProviderMvc/Controllers/UserController.cs b/samples/OpenIdProviderMvc/Controllers/UserController.cs index 5d46388..8b3f944 100644 --- a/samples/OpenIdProviderMvc/Controllers/UserController.cs +++ b/samples/OpenIdProviderMvc/Controllers/UserController.cs @@ -7,6 +7,14 @@ namespace OpenIdProviderMvc.Controllers { using System.Web.Mvc.Ajax; public class UserController : Controller { + public ActionResult PpidIdentity() { + if (Request.AcceptTypes.Contains("application/xrds+xml")) { + return View("PpidXrds"); + } + + return View(); + } + public ActionResult Identity(string id) { var redirect = this.RedirectIfNotNormalizedRequestUri(); if (redirect != null) { @@ -25,6 +33,10 @@ namespace OpenIdProviderMvc.Controllers { return View(); } + public ActionResult PpidXrds() { + return View(); + } + private ActionResult RedirectIfNotNormalizedRequestUri() { Uri normalized = Models.User.GetNormalizedClaimedIdentifier(Request.Url); if (Request.Url != normalized) { diff --git a/samples/OpenIdProviderMvc/Global.asax.cs b/samples/OpenIdProviderMvc/Global.asax.cs index b0d1b60..8c57961 100644 --- a/samples/OpenIdProviderMvc/Global.asax.cs +++ b/samples/OpenIdProviderMvc/Global.asax.cs @@ -22,6 +22,14 @@ "user/{id}/{action}", new { controller = "User", action = "Identity", id = string.Empty }); routes.MapRoute( + "PPID identifiers", + "anon", + new { controller = "User", action = "PpidIdentity", id = string.Empty }); + routes.MapRoute( + "PpidXrds", + "PpidXrds", + new { controller = "Home", action = "PpidXrds" }); // Parameter defaults + routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = string.Empty }); // Parameter defaults diff --git a/samples/OpenIdProviderMvc/Models/User.cs b/samples/OpenIdProviderMvc/Models/User.cs index 577aa05..198b8fa 100644 --- a/samples/OpenIdProviderMvc/Models/User.cs +++ b/samples/OpenIdProviderMvc/Models/User.cs @@ -5,17 +5,19 @@ using System.Text.RegularExpressions; using System.Web; using System.Web.Routing; + using OpenIdProviderMvc.Code; internal class User { + internal static Uri ClaimedIdentifierBaseUri { + get { return Util.GetAppPathRootedUri("user/"); } + } + internal static Uri GetClaimedIdentifierForUser(string username) { - string appPath = HttpContext.Current.Request.ApplicationPath; - if (!appPath.EndsWith("/")) { - appPath += "/"; + if (String.IsNullOrEmpty(username)) { + throw new ArgumentNullException("username"); } - Uri claimedIdentifier = new Uri( - HttpContext.Current.Request.Url, - appPath + "user/" + username); - return new Uri(claimedIdentifier.AbsoluteUri.ToLowerInvariant()); + + return new Uri(ClaimedIdentifierBaseUri, username.ToLowerInvariant()); } internal static string GetUserFromClaimedIdentifier(Uri claimedIdentifier) { diff --git a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj index 80e8e64..5caf26d 100644 --- a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj +++ b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj @@ -65,10 +65,12 @@ </ItemGroup> <ItemGroup> <Compile Include="Code\AccountMembershipService.cs" /> + <Compile Include="Code\AnonymousIdentifierProvider.cs" /> <Compile Include="Code\FormsAuthenticationService.cs" /> <Compile Include="Code\IFormsAuthentication.cs" /> <Compile Include="Code\IMembershipService.cs" /> <Compile Include="Code\ReadOnlyXmlMembershipProvider.cs" /> + <Compile Include="Code\Util.cs" /> <Compile Include="Controllers\AccountController.cs" /> <Compile Include="Controllers\HomeController.cs" /> <Compile Include="Controllers\OpenIdController.cs" /> @@ -90,8 +92,11 @@ <Content Include="Views\Account\ChangePassword.aspx" /> <Content Include="Views\Account\ChangePasswordSuccess.aspx" /> <Content Include="Views\Account\Register.aspx" /> + <Content Include="Views\Home\PpidXrds.aspx" /> <Content Include="Views\Home\Xrds.aspx" /> <Content Include="Views\OpenId\Provider.aspx" /> + <Content Include="Views\User\PpidXrds.aspx" /> + <Content Include="Views\User\PpidIdentity.aspx" /> <Content Include="Views\User\Identity.aspx" /> <Content Include="Views\User\Xrds.aspx" /> <Content Include="Web.config" /> @@ -117,6 +122,10 @@ <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project> <Name>DotNetOpenAuth</Name> </ProjectReference> + <ProjectReference Include="..\DotNetOpenAuth.ApplicationBlock\DotNetOpenAuth.ApplicationBlock.csproj"> + <Project>{AA78D112-D889-414B-A7D4-467B34C7B663}</Project> + <Name>DotNetOpenAuth.ApplicationBlock</Name> + </ProjectReference> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> diff --git a/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx b/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx new file mode 100644 index 0000000..990a3df --- /dev/null +++ b/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx @@ -0,0 +1,18 @@ +<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?> +<%-- +This page is a required as part of the service discovery phase of the openid +protocol (step 1). It simply renders the xml for doing service discovery of +server.aspx using the xrds mechanism. +This XRDS doc is discovered via the user.aspx page. +--%> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/server</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/samples/OpenIdProviderMvc/Views/Shared/Site.Master b/samples/OpenIdProviderMvc/Views/Shared/Site.Master index 8df2d5f..073908e 100644 --- a/samples/OpenIdProviderMvc/Views/Shared/Site.Master +++ b/samples/OpenIdProviderMvc/Views/Shared/Site.Master @@ -13,7 +13,7 @@ <div class="page"> <div id="header"> <div id="title"> - <h1>My MVC Application</h1> + <h1>OpenID Provider MVC Application</h1> </div> <div id="logindisplay"> <% Html.RenderPartial("LogOnUserControl"); %> diff --git a/samples/OpenIdProviderMvc/Views/User/Identity.aspx b/samples/OpenIdProviderMvc/Views/User/Identity.aspx index 632df43..bb50899 100644 --- a/samples/OpenIdProviderMvc/Views/User/Identity.aspx +++ b/samples/OpenIdProviderMvc/Views/User/Identity.aspx @@ -3,7 +3,7 @@ <%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider" TagPrefix="op" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> - <%=ViewData["username"]%> + <%=Html.Encode(ViewData["username"])%> identity page </asp:Content> <asp:Content runat="server" ContentPlaceHolderID="HeadContent"> @@ -12,7 +12,7 @@ </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>This is - <%=ViewData["username"]%>'s OpenID identity page </h2> + <%=Html.Encode(ViewData["username"])%>'s OpenID identity page </h2> <% if (string.Equals(User.Identity.Name, ViewData["username"])) { %> <p>This is <b>your</b> identity page. </p> diff --git a/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx b/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx new file mode 100644 index 0000000..f33a694 --- /dev/null +++ b/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx @@ -0,0 +1,16 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider" + TagPrefix="op" %> +<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> + Identity page +</asp:Content> +<asp:Content runat="server" ContentPlaceHolderID="HeadContent"> + <op:IdentityEndpoint ID="IdentityEndpoint11" runat="server" ProviderEndpointUrl="~/OpenId/PpidProvider" + ProviderVersion="V11" /> + <op:IdentityEndpoint ID="IdentityEndpoint20" runat="server" ProviderEndpointUrl="~/OpenId/PpidProvider" + XrdsUrl="~/User/all/ppidxrds" XrdsAutoAnswer="false" /> +</asp:Content> +<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> + <h2>OpenID identity page </h2> +</asp:Content> diff --git a/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx b/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx new file mode 100644 index 0000000..67256bd --- /dev/null +++ b/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx @@ -0,0 +1,13 @@ +<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?> +<XRDS xmlns="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0"> + <XRD xmlns="xri://$xrd*($v*2.0)"> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI> + </Service> + <Service priority="20"> + <Type>http://openid.net/signon/1.0</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI> + </Service> + </XRD> +</XRDS> |