diff options
7 files changed, 89 insertions, 12 deletions
diff --git a/samples/OpenIdProviderMvc/Code/FormsAuthenticationService.cs b/samples/OpenIdProviderMvc/Code/FormsAuthenticationService.cs index 22db860..1f5ea54 100644 --- a/samples/OpenIdProviderMvc/Code/FormsAuthenticationService.cs +++ b/samples/OpenIdProviderMvc/Code/FormsAuthenticationService.cs @@ -10,6 +10,18 @@ get { return HttpContext.Current.User.Identity.Name; } } + public DateTime? SignedInTimestampUtc { + get { + var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName]; + if (cookie != null) { + var ticket = FormsAuthentication.Decrypt(cookie.Value); + return ticket.IssueDate.ToUniversalTime(); + } else { + return null; + } + } + } + public void SignIn(string userName, bool createPersistentCookie) { FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); } diff --git a/samples/OpenIdProviderMvc/Code/IFormsAuthentication.cs b/samples/OpenIdProviderMvc/Code/IFormsAuthentication.cs index d4c8a01..09856e9 100644 --- a/samples/OpenIdProviderMvc/Code/IFormsAuthentication.cs +++ b/samples/OpenIdProviderMvc/Code/IFormsAuthentication.cs @@ -17,6 +17,8 @@ using System.Web.Security; public interface IFormsAuthentication { string SignedInUsername { get; } + DateTime? SignedInTimestampUtc { get; } + void SignIn(string userName, bool createPersistentCookie); void SignOut(); diff --git a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs index 198c434..4782e94 100644 --- a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs +++ b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs @@ -17,6 +17,16 @@ namespace OpenIdProviderMvc.Controllers { public class OpenIdController : Controller { internal static OpenIdProvider OpenIdProvider = new OpenIdProvider(); + public OpenIdController() + : this(null) { + } + + public OpenIdController(IFormsAuthentication formsAuthentication) { + this.FormsAuth = formsAuthentication ?? new FormsAuthenticationService(); + } + + public IFormsAuthentication FormsAuth { get; private set; } + [ValidateInput(false)] public ActionResult Provider() { IRequest request = OpenIdProvider.GetRequest(); @@ -29,25 +39,44 @@ namespace OpenIdProviderMvc.Controllers { // This is apparently one that the host (the web site itself) has to respond to. ProviderEndpoint.PendingRequest = (IHostProcessedRequest)request; - // Try responding immediately if possible. - ActionResult response; - if (this.AutoRespondIfPossible(out response)) { - return response; - } - - // We can't respond immediately with a positive result. But if we still have to respond immediately... - if (ProviderEndpoint.PendingRequest.Immediate) { - // We can't stop to prompt the user -- we must just return a negative response. - return this.SendAssertion(); + // If PAPE requires that the user has logged in recently, we may be required to challenge the user to log in. + var papeRequest = ProviderEndpoint.PendingRequest.GetExtension<PolicyRequest>(); + if (papeRequest != null && papeRequest.MaximumAuthenticationAge.HasValue) { + TimeSpan timeSinceLogin = DateTime.UtcNow - this.FormsAuth.SignedInTimestampUtc.Value; + if (timeSinceLogin > papeRequest.MaximumAuthenticationAge.Value) { + // The RP wants the user to have logged in more recently than he has. + // We'll have to redirect the user to a login screen. + return this.RedirectToAction("LogOn", "Account", new { returnUrl = this.Url.Action("ProcessAuthRequest") }); + } } - return this.RedirectToAction("AskUser"); + return this.ProcessAuthRequest(); } else { // No OpenID request was recognized. This may be a user that stumbled on the OP Endpoint. return this.View(); } } + public ActionResult ProcessAuthRequest() { + if (ProviderEndpoint.PendingRequest == null) { + return this.RedirectToAction("Index", "Home"); + } + + // Try responding immediately if possible. + ActionResult response; + if (this.AutoRespondIfPossible(out response)) { + return response; + } + + // We can't respond immediately with a positive result. But if we still have to respond immediately... + if (ProviderEndpoint.PendingRequest.Immediate) { + // We can't stop to prompt the user -- we must just return a negative response. + return this.SendAssertion(); + } + + return this.RedirectToAction("AskUser"); + } + /// <summary> /// Displays a confirmation page. /// </summary> @@ -133,6 +162,17 @@ namespace OpenIdProviderMvc.Controllers { pendingRequest.AddResponseExtension(claimsResponse); } + + // Look for PAPE requests. + var papeRequest = pendingRequest.GetExtension<PolicyRequest>(); + if (papeRequest != null) { + var papeResponse = new PolicyResponse(); + if (papeRequest.MaximumAuthenticationAge.HasValue) { + papeResponse.AuthenticationTimeUtc = this.FormsAuth.SignedInTimestampUtc; + } + + pendingRequest.AddResponseExtension(papeResponse); + } } return OpenIdProvider.PrepareResponse(pendingRequest).AsActionResult(); diff --git a/samples/OpenIdRelyingPartyWebForms/MembersOnly/Default.aspx b/samples/OpenIdRelyingPartyWebForms/MembersOnly/Default.aspx index cbc13ee..59a4eed 100644 --- a/samples/OpenIdRelyingPartyWebForms/MembersOnly/Default.aspx +++ b/samples/OpenIdRelyingPartyWebForms/MembersOnly/Default.aspx @@ -18,6 +18,9 @@ <% } foreach (string policy in State.PapePolicies.ActualPolicies) { %> <li><%=HttpUtility.HtmlEncode(policy) %></li> + <% } + if (State.PapePolicies.AuthenticationTimeUtc.HasValue) { %> + <li>The provider authenticated the user at <%=State.PapePolicies.AuthenticationTimeUtc.Value.ToLocalTime() %> (local time)</li> <% } %> </ul> <% } %> diff --git a/samples/OpenIdRelyingPartyWebForms/login.aspx b/samples/OpenIdRelyingPartyWebForms/login.aspx index 98eee7a..17a230a 100644 --- a/samples/OpenIdRelyingPartyWebForms/login.aspx +++ b/samples/OpenIdRelyingPartyWebForms/login.aspx @@ -20,6 +20,10 @@ <asp:ListItem Text="Request physical multi-factor authentication" Value="http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical" /> <asp:ListItem Text="Request PPID identifier" Value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" /> </asp:CheckBoxList> + <p>Request that the Provider have authenticated the user in the last + <asp:TextBox runat="server" ID="maxAuthTimeBox" MaxLength="4" Columns="4" /> + seconds. + </p> <p>Try the PPID identifier functionality against the OpenIDProviderMvc sample.</p> </fieldset> <p><a href="loginGoogleApps.aspx">Log in using Google Apps for Domains</a>. </p> diff --git a/samples/OpenIdRelyingPartyWebForms/login.aspx.cs b/samples/OpenIdRelyingPartyWebForms/login.aspx.cs index 6721e9b..9c7eb7a 100644 --- a/samples/OpenIdRelyingPartyWebForms/login.aspx.cs +++ b/samples/OpenIdRelyingPartyWebForms/login.aspx.cs @@ -45,12 +45,19 @@ namespace OpenIdRelyingPartyWebForms { } // Add the PAPE extension if any policy was requested. + var pape = new PolicyRequest(); if (policies.Count > 0) { - var pape = new PolicyRequest(); foreach (string policy in policies) { pape.PreferredPolicies.Add(policy); } + } + + if (maxAuthTimeBox.Text.Length > 0) { + pape.MaximumAuthenticationAge = TimeSpan.FromSeconds(double.Parse(maxAuthTimeBox.Text)); + } + + if (pape.PreferredPolicies.Count > 0 || pape.MaximumAuthenticationAge.HasValue) { request.AddExtension(pape); } } diff --git a/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs index 017d259..9ee9edc 100644 --- a/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs +++ b/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs @@ -40,6 +40,15 @@ namespace OpenIdRelyingPartyWebForms { protected global::System.Web.UI.WebControls.CheckBoxList papePolicies; /// <summary> + /// maxAuthTimeBox 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.TextBox maxAuthTimeBox; + + /// <summary> /// yahooLoginButton control. /// </summary> /// <remarks> |